<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>http://wiki.fhem.de/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ch.eick</id>
	<title>FHEMWiki - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.fhem.de/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ch.eick"/>
	<link rel="alternate" type="text/html" href="http://wiki.fhem.de/wiki/Spezial:Beitr%C3%A4ge/Ch.eick"/>
	<updated>2026-06-28T16:36:40Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=40270</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=40270"/>
		<updated>2025-06-24T16:41:39Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Screenshot 2024-01-23 122115.png|mini|400px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrhythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
# {{Link2Forum|Topic=130407|LinkText=Tibber - im Forum}}&lt;br /&gt;
# {{Link2Forum|Topic=135906|LinkText=aWATTar - im Forum}}&lt;br /&gt;
# {{Link2Forum|Topic=135906|LinkText=EPEX_Spot}}&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im Folgenden beschriebenen Beispieldevices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht unterstützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* homeID und personal Token/Access Token/Connect Token&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== Token ===&lt;br /&gt;
Der Token wird leider unterschiedlich bezeichnet, aber egal ob er personal Token, Access Token oder Connect Token heisst, es bezieht sich auf den gleichen. &lt;br /&gt;
&lt;br /&gt;
Erhältlich ist dieser aktuell (Oktober 24) unter https://developer.tibber.com/ &lt;br /&gt;
&lt;br /&gt;
Dort bitte mit deinen Zugangsdaten einloggen (&amp;quot;Sign In&amp;quot;, oben rechts) und man bekommt den Access Token direkt angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== homeID ===&lt;br /&gt;
Um eine HomeID zu erhalten, muss zuerst der Pulse mit dem Internet bzw. tibber verbunden werden. Wenn die App glücklich ist, gehts hier weiter: &lt;br /&gt;
&lt;br /&gt;
Man loggt sich wieder ein unter https://developer.tibber.com/. Dort geht man dann zum API Explorer. &lt;br /&gt;
&lt;br /&gt;
Leider ist keine der Demo-Abfragen geeignet, die homeID zu erfahren. Dafür gibt man ins linke fenster folgenden Code ein: &amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  viewer {&lt;br /&gt;
    homes {&lt;br /&gt;
      id&lt;br /&gt;
      address {&lt;br /&gt;
        address1&lt;br /&gt;
        postalCode&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dann startet man mit dem Play-Pfeil und bekommt auf der rechten Seite etwa folgende Ausgabe: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;data&amp;quot;: {&lt;br /&gt;
    &amp;quot;viewer&amp;quot;: {&lt;br /&gt;
      &amp;quot;homes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;id&amp;quot;: &amp;quot;1234abcd-12ab-34cd-56ef-1234abcd12ab&lt;br /&gt;
          &amp;quot;address&amp;quot;: {&lt;br /&gt;
            &amp;quot;address1&amp;quot;: &amp;quot;Musterstr.1&amp;quot;,&lt;br /&gt;
            &amp;quot;postalCode&amp;quot;: &amp;quot;12345&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      ]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Diese ID ist die homeID und kann unten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD Statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* Die WebSocket Verbindung wurde leicht angepasst &#039;&#039;&#039;[[Websocket|von hier]]&#039;&#039;&#039; übernommen&lt;br /&gt;
* Im Forum wurde dies &#039;&#039;&#039;{{Link2Forum|Topic=130407|Message=1298863|LinkText=ab hier}}&#039;&#039;&#039; bearbeitet&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preisen bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht versehentlich seine Daten im Forum postet.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWATTar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind.&lt;br /&gt;
* Die bisherige Berechnung mit Stand 20240123 wäre wie folgt: round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. EPEX_Spot ==&lt;br /&gt;
Das Device ist noch experimentell.&lt;br /&gt;
=== Vorausetzungen ===&lt;br /&gt;
httpmod&lt;br /&gt;
&lt;br /&gt;
==== EPEX_Spot  RAW Device ====&lt;br /&gt;
Mit zwei set kann man &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EPEX_Spot HTTPMOD none&lt;br /&gt;
attr EPEX_Spot comment https://api.energy-charts.info\&lt;br /&gt;
https://api.energy-charts.info/price?bzn=DE-LU&amp;amp;start=2025-06-25&amp;amp;end=2025-06-25\&lt;br /&gt;
\&lt;br /&gt;
https://api.energy-charts.info/price?bzn=DE-LU 3600&lt;br /&gt;
attr EPEX_Spot disable 0&lt;br /&gt;
attr EPEX_Spot extractAllJSON 0&lt;br /&gt;
attr EPEX_Spot get01-0Name fc0_00_total&lt;br /&gt;
attr EPEX_Spot get01-0OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-10Name fc0_09&lt;br /&gt;
attr EPEX_Spot get01-10OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-11Name fc0_10&lt;br /&gt;
attr EPEX_Spot get01-11OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-12Name fc0_11&lt;br /&gt;
attr EPEX_Spot get01-12OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-13Name fc0_12&lt;br /&gt;
attr EPEX_Spot get01-13OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-14Name fc0_13&lt;br /&gt;
attr EPEX_Spot get01-14OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-15Name fc0_14&lt;br /&gt;
attr EPEX_Spot get01-15OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-16Name fc0_15&lt;br /&gt;
attr EPEX_Spot get01-16OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-17Name fc0_16&lt;br /&gt;
attr EPEX_Spot get01-17OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-18Name fc0_17&lt;br /&gt;
attr EPEX_Spot get01-18OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-19Name fc0_18&lt;br /&gt;
attr EPEX_Spot get01-19OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-1Name fc0_00&lt;br /&gt;
attr EPEX_Spot get01-1OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-20Name fc0_19&lt;br /&gt;
attr EPEX_Spot get01-20OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-21Name fc0_20&lt;br /&gt;
attr EPEX_Spot get01-21OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-22Name fc0_21&lt;br /&gt;
attr EPEX_Spot get01-22OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-23Name fc0_22&lt;br /&gt;
attr EPEX_Spot get01-23OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-24Name fc0_23&lt;br /&gt;
attr EPEX_Spot get01-24OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-2Name fc0_01&lt;br /&gt;
attr EPEX_Spot get01-2OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-3Name fc0_02&lt;br /&gt;
attr EPEX_Spot get01-3OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-4Name fc0_03&lt;br /&gt;
attr EPEX_Spot get01-4OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-5Name fc0_04&lt;br /&gt;
attr EPEX_Spot get01-5OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-6Name fc0_05&lt;br /&gt;
attr EPEX_Spot get01-6OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-7Name fc0_06&lt;br /&gt;
attr EPEX_Spot get01-7OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-8Name fc0_07&lt;br /&gt;
attr EPEX_Spot get01-8OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01-9Name fc0_08&lt;br /&gt;
attr EPEX_Spot get01-9OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get01Name 01_priceinfo_today&lt;br /&gt;
attr EPEX_Spot get01RegOpt g&lt;br /&gt;
attr EPEX_Spot get01Regex [price&amp;quot;:\[|,](-?\d+\.\d+)&lt;br /&gt;
attr EPEX_Spot get01URL https://api.energy-charts.info/price?bzn=DE-LU&amp;amp;start=%%start_today%%&lt;br /&gt;
attr EPEX_Spot get02-0Name fc1_00_total&lt;br /&gt;
attr EPEX_Spot get02-0OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-10Name fc1_09&lt;br /&gt;
attr EPEX_Spot get02-10OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-11Name fc1_10&lt;br /&gt;
attr EPEX_Spot get02-11OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-12Name fc1_11&lt;br /&gt;
attr EPEX_Spot get02-12OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-13Name fc1_12&lt;br /&gt;
attr EPEX_Spot get02-13OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-14Name fc1_13&lt;br /&gt;
attr EPEX_Spot get02-14OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-15Name fc1_14&lt;br /&gt;
attr EPEX_Spot get02-15OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-16Name fc1_15&lt;br /&gt;
attr EPEX_Spot get02-16OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-17Name fc1_16&lt;br /&gt;
attr EPEX_Spot get02-17OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-18Name fc1_17&lt;br /&gt;
attr EPEX_Spot get02-18OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-19Name fc1_18&lt;br /&gt;
attr EPEX_Spot get02-19OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-1Name fc1_00&lt;br /&gt;
attr EPEX_Spot get02-1OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-20Name fc1_19&lt;br /&gt;
attr EPEX_Spot get02-20OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-21Name fc1_20&lt;br /&gt;
attr EPEX_Spot get02-21OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-22Name fc1_21&lt;br /&gt;
attr EPEX_Spot get02-22OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-23Name fc1_22&lt;br /&gt;
attr EPEX_Spot get02-23OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-24Name fc1_23&lt;br /&gt;
attr EPEX_Spot get02-24OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-2Name fc1_01&lt;br /&gt;
attr EPEX_Spot get02-2OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-3Name fc1_02&lt;br /&gt;
attr EPEX_Spot get02-3OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-4Name fc1_03&lt;br /&gt;
attr EPEX_Spot get02-4OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-5Name fc1_04&lt;br /&gt;
attr EPEX_Spot get02-5OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-6Name fc1_05&lt;br /&gt;
attr EPEX_Spot get02-6OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-7Name fc1_06&lt;br /&gt;
attr EPEX_Spot get02-7OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-8Name fc1_07&lt;br /&gt;
attr EPEX_Spot get02-8OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02-9Name fc1_08&lt;br /&gt;
attr EPEX_Spot get02-9OExpr round($val,2)&lt;br /&gt;
attr EPEX_Spot get02Name 02_priceinfo_tomorrow&lt;br /&gt;
attr EPEX_Spot get02RegOpt g&lt;br /&gt;
attr EPEX_Spot get02Regex [price&amp;quot;:\[|,](-?\d+\.\d+)&lt;br /&gt;
attr EPEX_Spot get02URL https://api.energy-charts.info/price?bzn=DE-LU&amp;amp;start=%%start_tomorrow%%&lt;br /&gt;
attr EPEX_Spot group price&lt;br /&gt;
attr EPEX_Spot icon stromzaehler_icon&lt;br /&gt;
attr EPEX_Spot replacement01Mode expression&lt;br /&gt;
attr EPEX_Spot replacement01Regex %%start_today%%&lt;br /&gt;
attr EPEX_Spot replacement01Value strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))&lt;br /&gt;
attr EPEX_Spot replacement02Mode expression&lt;br /&gt;
attr EPEX_Spot replacement02Regex %%start_tomorrow%%&lt;br /&gt;
attr EPEX_Spot replacement02Value strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time()+86400))&lt;br /&gt;
attr EPEX_Spot room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EPEX_Spot showBody 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Website (deutsch) des Anbieters [https://tibber.com/de Tibber]&lt;br /&gt;
* Website (deutsch) des Anbieters [https://www.awattar.de/ aWATTar]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=40061</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=40061"/>
		<updated>2025-03-17T09:10:46Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus G1-G3&lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
- Piko CI 30&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatiblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Kostal Piko CI 30 mit dem ModbusAttr Modul&lt;br /&gt;
Die Modbus-Attribute können zum großen Teil übernommen werden, aber Kostal fängt bei diesem Modell nicht bei &amp;quot;0&amp;quot;, sondern bei &amp;quot;1&amp;quot; an zu zählen. Das heißt, alle [https://cdn-production.kostal.com/-/media/document-library-folder---kse/2023/11/20/15/12/ba_kostal-interface-description-modbus_piko-ci.pdf Modbus-Adressen die hier genannt werden], müssen um 1 vermindert werden.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.&#039;dwd_load&#039; TO &#039;fhemuser&#039;@&#039;%&#039;;             &amp;lt;&amp;lt;&amp;lt;&amp;lt; Das beschränkt auf nur eine Prozedure&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Es könnte auch gut sein einen extra root user anzulegen, um mit DbRep die MySQL Datenbank zu optimieren&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; GRANT ALL PRIVILEGES ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; WITH GRANT OPTION;&lt;br /&gt;
mysql&amp;gt; GRANT SHOW_ROUTINE ON *.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE, CREATE ROUTINE, ALTER ROUTINE ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT user,host FROM mysql.user;&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| user             | host           |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| fhemuser         | %              |&lt;br /&gt;
| fhemroot         | 192.168.178.57 |   &amp;lt;&amp;lt;&amp;lt; Das sollte man dann auf eine IP einschränken.&lt;br /&gt;
| root             | localhost      |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
&lt;br /&gt;
-- Hier kann man mal seine Proceduren auflisten&lt;br /&gt;
mysql&amp;gt; SHOW PROCEDURE STATUS WHERE Db = &#039;fhem&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy              # Version 1.2.18&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wird mit folgenden Parametern aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=40060</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=40060"/>
		<updated>2025-03-17T08:55:46Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* KI Prognose Teil 3 - Python KI Prognose Skript */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.&#039;dwd_load&#039; TO &#039;fhemuser&#039;@&#039;%&#039;;             &amp;lt;&amp;lt;&amp;lt;&amp;lt; Das beschränkt auf nur eine Prozedure&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Es könnte auch gut sein einen extra root user anzulegen, um mit DbRep die MySQL Datenbank zu optimieren&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; GRANT ALL PRIVILEGES ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; WITH GRANT OPTION;&lt;br /&gt;
mysql&amp;gt; GRANT SHOW_ROUTINE ON *.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE, CREATE ROUTINE, ALTER ROUTINE ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT user,host FROM mysql.user;&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| user             | host           |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| fhemuser         | %              |&lt;br /&gt;
| fhemroot         | 192.168.178.57 |   &amp;lt;&amp;lt;&amp;lt; Das sollte man dann auf eine IP einschränken.&lt;br /&gt;
| root             | localhost      |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
&lt;br /&gt;
-- Hier kann man mal seine Proceduren auflisten&lt;br /&gt;
mysql&amp;gt; SHOW PROCEDURE STATUS WHERE Db = &#039;fhem&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy              # Version 1.2.18&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wird mit folgenden Parametern aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=OpenWB&amp;diff=39803</id>
		<title>OpenWB</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=OpenWB&amp;diff=39803"/>
		<updated>2025-01-12T15:57:25Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Node-red */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Integration der openWB in FHEM - Ladeleistung anzeigen und Umschalten des Lademodus ==&lt;br /&gt;
Ausgangssituation ist ein funktionierendes FHEM, ohne weitere Vorbedingungen.&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod openwb MQTT &amp;lt;openWBip&amp;gt;:1883&lt;br /&gt;
attr openwb room Auto,MQTT&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Dadurch wird der MQTT-Server der openWB angesprochen, FHEM ist der Client.&lt;br /&gt;
&lt;br /&gt;
Ein Ladepunkt wird als MQTT_Device angelegt:&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod lp1 MQTT_DEVICE&lt;br /&gt;
attr lp1 IODev openwb&lt;br /&gt;
attr lp1 publishSet_chargeMode openWB/set/ChargeMode&lt;br /&gt;
attr lp1 room Auto,Dashboard,MQTT&lt;br /&gt;
attr lp1 stateFormat power&lt;br /&gt;
attr lp1 subscribeReading_chargeMode openWB/global/ChargeMode&lt;br /&gt;
attr lp1 subscribeReading_plugStat openWB/lp/1/boolPlugStat&lt;br /&gt;
attr lp1 subscribeReading_power openWB/lp/1/W&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Die Umsetzung basiert auf openWB 1.9.x, der Lademodus &amp;quot;ChargeMode&amp;quot; gilt hier noch global für alle Ladepunkte.&lt;br /&gt;
&lt;br /&gt;
Beispielhaft die Definition des zweiten Ladepunktes, eine zweite openWB, die als &amp;quot;nur Ladepunkt&amp;quot; mit der angesprochenen openWB verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Eine openWB kann derzeit 8 Ladepunkte verwalten, die Nummern müssen entsprechend inkrementiert werden.&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod lp2 MQTT_DEVICE&lt;br /&gt;
attr lp2 IODev openwb&lt;br /&gt;
attr lp2 publishSet_chargeMode openWB/set/ChargeMode&lt;br /&gt;
attr lp2 room Auto,Dashboard,MQTT&lt;br /&gt;
attr lp2 stateFormat power&lt;br /&gt;
attr lp2 subscribeReading_chargeMode openWB/global/ChargeMode&lt;br /&gt;
attr lp2 subscribeReading_plugStat openWB/lp/2/boolPlugStat&lt;br /&gt;
attr lp2 subscribeReading_power openWB/lp/2/W&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Die MQTT-Topics zum Lesen und Schreiben von Werten sind ganz unten auf dieser Wiki-Seite zu finden.&lt;br /&gt;
&lt;br /&gt;
Die Einbindung in die TabletUI sieht bei mir so aus:&lt;br /&gt;
[[Datei:Ladepunkte in TabletUI.png|alternativtext=Darstellung der openWB Ladepunkte in der TabletUI|mini|488x488px|Beispielhafte Darstellung in der TabletUI]]&lt;br /&gt;
[[Datei:Auswahl des Lademodus.png|alternativtext=Darstellung der openWB Ladepunkte in der TabletUI - Auswahl des Lademodus|mini|486x486px|Auswahl des Lademodus per CircleMenu]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;cell-60 left-space right-space&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;div data-type=&amp;quot;symbol&amp;quot; data-icon=&amp;quot;fa-car&amp;quot; class=&amp;quot;tall compressed&amp;quot; data-color=&amp;quot;lightgray&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;div data-type=&amp;quot;circlemenu&amp;quot; data-direction=&amp;quot;full&amp;quot; class=&amp;quot;mini&amp;quot; style=&amp;quot;top: -0.5em;&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ul class=&amp;quot;mini&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-states=&#039;[0,1,2,3,4]&#039; data-colors=&#039;[&amp;quot;lightgreen&amp;quot;,&amp;quot;greenyellow&amp;quot;,&amp;quot;yellow&amp;quot;,&amp;quot;grey&amp;quot;,&amp;quot;black&amp;quot;]&#039; data-icons=&#039;[&amp;quot;fa-bolt&amp;quot;,&amp;quot;fa-plus-circle&amp;quot;,&amp;quot;fa-sun-o&amp;quot;,&amp;quot;fa-pause-circle-o&amp;quot;,&amp;quot;fa-stop-circle-o&amp;quot;]&#039; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;0&amp;quot; data-get-on=&amp;quot;0&amp;quot; data-icon=&amp;quot;fa-bolt&amp;quot; data-color=&amp;quot;lightgreen&amp;quot;  data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;1&amp;quot; data-get-on=&amp;quot;1&amp;quot; data-icon=&amp;quot;fa-plus-circle&amp;quot; data-color=&amp;quot;greenyellow&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;2&amp;quot; data-get-on=&amp;quot;2&amp;quot; data-icon=&amp;quot;fa-sun-o&amp;quot; data-color=&amp;quot;yellow&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;3&amp;quot; data-get-on=&amp;quot;3&amp;quot; data-icon=&amp;quot;fa-pause-circle-o&amp;quot; data-color=&amp;quot;grey&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;4&amp;quot; data-get-on=&amp;quot;4&amp;quot; data-icon=&amp;quot;fa-stop-circle-o&amp;quot; data-color=&amp;quot;black&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
			&amp;lt;/ul&amp;gt;&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;div style=&amp;quot;font-size: 30% !important;&amp;quot; class=&amp;quot;mini &amp;quot; data-pre-text=&amp;quot;&amp;quot; data-type=&amp;quot;label&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;power&amp;quot; data-unit=&amp;quot;&amp;quot; data-factor=&amp;quot;1&amp;quot; data-fix=&amp;quot;0&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;div data-type=&amp;quot;symbol&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;plugStat&amp;quot; data-states=&#039;[0,1]&#039; data-colors=&#039;[&amp;quot;white&amp;quot;,&amp;quot;black&amp;quot;]&#039; data-icons=&#039;[&amp;quot;&amp;quot;,&amp;quot;fa-plug&amp;quot;]&#039; data-background-icon=&amp;quot;&amp;quot; class=&amp;quot;mini&amp;quot; style=&amp;quot;font-size: 30% !important; top:1em;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Integration OpenWB in FHEM - Übertragung von EVU, PV und Batteriewerten an openWB==&lt;br /&gt;
Ausgangssituation ist ein funktionierendes FHEM-System, bei dem bereits der digitale Stromzähler (&amp;quot;Moderne Meßeinrichtung&amp;quot;) über das Modul 47_OBIS und der PV-Wechselrichter über ein entsprechendes Modul, z.B. ModbusAttr integriert sind. Als OpenWB-System wurde hier eine reale OpenWB-Wallbox angebunden.&lt;br /&gt;
&lt;br /&gt;
=== Datenquellen ===&lt;br /&gt;
Die OpenWB erwartet 1-3 Typen von Datenquellen in dieser Konstellation:&lt;br /&gt;
* Die &#039;&#039;EVU-&#039;&#039;Schnittstelle, mit der als wesentlicher Steuerparameter der Ladeleistung die Leistungsmessung am Hausübergang herangezogen wird, und daneben die Zählerwerte für Netzbezug und Einspeisung zur Visualisierung übertragen werden sollten. Nur, falls phasenbezogenes Lastmanagement erforderlich sein sollte, sind auch die einzelnen Phasenleistungswerte vom Stromzähler nötig (was nicht jede Moderne Meßeinrichtung auf der OBIS-Schnittstelle bereitstellt)&lt;br /&gt;
* Die &#039;&#039;PV-&#039;&#039;Schnittstelle, die ebenfalls primär visualisierende Bedeutung hat.&lt;br /&gt;
* Die &#039;&#039;Batteriespeicher-&#039;&#039;Schnittstelle&lt;br /&gt;
OpenWB kann auch z.B. rein mit einer PV-Schnittstelle betrieben werden, in diesem Fall wird ein konstanter Leistungswert für den Hausbezug angenommen.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikationsprotokoll ===&lt;br /&gt;
Zur Kommunikation mit FHEM bieten sich 2 Methoden an:&lt;br /&gt;
* &#039;&#039;&#039;HTTP&#039;&#039;&#039;-Abfrage durch OpenWB bei FHEM durch das generische HTTP-Modul von OpenWB  Diese Methode beschreibe ich nicht, weil sie mehr Overhead erzeugt und seitens FHEM die Einrichtung eines CSRF-Token-freien Web-Kanals erfordert&lt;br /&gt;
* &#039;&#039;&#039;MQTT&#039;&#039;&#039;-Push durch FHEM zur OpenWB  Diese Methode erscheint mir vorteilhafter, weil auf einer stehenden TCP-Verbindung lediglich Meßwerte gepusht werden.&lt;br /&gt;
&lt;br /&gt;
=== Implementierung ===&lt;br /&gt;
&lt;br /&gt;
==== Vorbereitung ====&lt;br /&gt;
In der OpenWB-Web-UI unter Modulkonfiguration die entsprechenden Module (EVU, PV, Batterie) auf MQTT stellen. Hinweis: Nicht alle dabei erscheinenden MQTT-Topics müssen mit Werten beliefert werden! Sowohl bei der EVU-Schnittstelle wie bei PV reichen Momentanleistung und Zählerstände für eine zufriedenstellende Anbindung!&lt;br /&gt;
&lt;br /&gt;
==== Definition der OpenWB als MQTT-Target ====&lt;br /&gt;
 defmod openwb_mqtt MQTT2_CLIENT &amp;lt;ip-der-openwb&amp;gt;:1883&lt;br /&gt;
 attr openwb_mqtt autocreate simple&lt;br /&gt;
 attr openwb_mqtt subscriptions openWB/lp/1/#&lt;br /&gt;
&lt;br /&gt;
==== Übertragung der EVU-Meßwerte ====&lt;br /&gt;
In diesem Beispiel heißt das die Stromzählerdaten liefernde Device am OBIS-Modul &amp;quot;MT175&amp;quot;. Die Zahlen werden per Notify von diesem Device auf MQTT kopiert:&lt;br /&gt;
 defmod openwb_evu_cons notify MT175:total_consumption:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/WhImported &amp;quot; . $EVTPART1); }&lt;br /&gt;
 defmod openwb_evu_feed notify MT175:total_feed:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/WhExported &amp;quot; . $EVTPART1); }&lt;br /&gt;
 defmod openwb_evu_w notify MT175:power:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/W &amp;quot; . int($EVTPART1)); }&lt;br /&gt;
&lt;br /&gt;
==== Übertragung der PV-Meßwerte ====&lt;br /&gt;
Sofern die Daten für Momentanleistung und Zählerstand direkt in einem Device vorliegen, können analoge Notifys für dieses Device implementiert werden. Die Zielwerte lauten:&lt;br /&gt;
* Für den Momentan-Leistungswert &amp;lt;code&amp;gt;openWB/set/pv/1/W&amp;lt;/code&amp;gt;&lt;br /&gt;
* Für den Zählerstand &amp;lt;code&amp;gt;openWB/set/pv/1/WhCounter&amp;lt;/code&amp;gt;&lt;br /&gt;
Dabei muss beachtet werden, dass - wie bei der EVU-Schnittstelle - nur Integerwerte für die Momentanleistung übertragen werden dürfen.&lt;br /&gt;
&lt;br /&gt;
==== Anbindung an Alexa ====&lt;br /&gt;
Der generische Smarthome-Skill &amp;quot;FHEMConnector&amp;quot; erlaubt nur die leider immer noch sehr limitierte Syntax von Amazon Alexa. Im Folgenden werden die Definitionen für die Befehle:&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen ein&amp;quot;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen aus&amp;quot;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen auf 6 (Prozent)&amp;quot;&#039;&#039;&lt;br /&gt;
dargestellt. &amp;quot;Überschussladen auf 6&amp;quot; bedeutet dabei real den &amp;quot;Min+PV&amp;quot;, also Überschussladen mit Minimalleistung von 6 Ampere. Je nach Tagesform von Amazon ist dabei das Sprechen von &amp;quot;Prozent&amp;quot; nötig, auch wenn dies natürlich sachlich falsch ist.&lt;br /&gt;
 define openwb_ueberschuss dummy&lt;br /&gt;
 attr openwb_ueberschuss alexaName Überschussladen&lt;br /&gt;
 attr openwb_ueberschuss genericDeviceType light&lt;br /&gt;
 attr openwb_ueberschuss readingList pct&lt;br /&gt;
 attr openwb_ueberschuss setList on off pct&lt;br /&gt;
 define openwb_ueberschuss_on notify openwb_ueberschuss:on set openwb_mqtt publish openWB/set/ChargeMode 2&lt;br /&gt;
 define openwb_ueberschuss_off notify openwb_ueberschuss:off set openwb_mqtt publish openWB/set/ChargeMode 3&lt;br /&gt;
 define openwb_ueberschuss_pct notify openwb_ueberschuss:pct:.* set openwb_mqtt publish openWB/config/set/pv/minCurrentMinPv $EVTPART1 ;; set openwb_mqtt publish openWB/set/ChargeMode 1&lt;br /&gt;
&lt;br /&gt;
==Anwendungs Beispiele==&lt;br /&gt;
===Komplexe Anbindung===&lt;br /&gt;
[[Bild:Kia.PNG|mini|700px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
Hier mal ein Beispiel mit weiteren Schnittstellen in der Haussteuerung. Im Hintergrund arbeitet ein Wechselrichter Schwarm mit einem Hausspeicher, der beim BEV Laden gesperrt wird. Die openWB kommuniziert direkt mit den zwei Kostal Wechselrichtern, dem KSEM und dem am Master angeschlossenen Speicher. Das BEV ist über Kia Connect angebunden.&lt;br /&gt;
[[Bild:WB_1.PNG|mini|700px|rechts|openWB mit Statistiken]]&lt;br /&gt;
[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss, inklusive Wechselrichter, raus kommen. Die openWBs sind unten links.]]&lt;br /&gt;
====Verwendete Schnittstellen / Devices====&lt;br /&gt;
=====openWB MQTT=====&lt;br /&gt;
Wie oben beschrieben mit folgender MQTT definition. Im Bild ist das DOIF dargestellt und das MQTT Device als kurze Darstellung unterhalb der Tabelle. Das MQTT wird nur zur Kopplung verwendet, hat jedoch jetzt auch ein stateFormat inklusieve Statistiken erhalten.&lt;br /&gt;
&lt;br /&gt;
RAW des MQTT Device&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WB_1 MQTT2_DEVICE WB_1_MQTT2&lt;br /&gt;
attr WB_1 DbLogExclude .*&lt;br /&gt;
attr WB_1 DbLogInclude lp_1_.*,.*AllChargePoints.*,ChargeMode&lt;br /&gt;
attr WB_1 IODev WB_1_MQTT2&lt;br /&gt;
attr WB_1 alias WB_1&lt;br /&gt;
attr WB_1 autocreate 0&lt;br /&gt;
attr WB_1 comment Die openWB besteht aus zwei Ladepunkten.&lt;br /&gt;
attr WB_1 devicetopic openWB&lt;br /&gt;
attr WB_1 disable 0&lt;br /&gt;
attr WB_1 event-on-change-reading lp_1_.*,.*AllChargePoints.*,ChargeMode&lt;br /&gt;
attr WB_1 group PV Eigenverbrauch&lt;br /&gt;
attr WB_1 icon fuel&lt;br /&gt;
attr WB_1 readingList $DEVICETOPIC/global/WHouseConsumption:.* WHouseConsumption\&lt;br /&gt;
$DEVICETOPIC/global/WAllChargePoints:.* WAllChargePoints\&lt;br /&gt;
$DEVICETOPIC/global/ChargeMode:.* {my %h=(0=&amp;gt;&#039;SofortLaden&#039;,1=&amp;gt;&#039;MinPV&#039;,2=&amp;gt;&#039;NurPV&#039;,3=&amp;gt;&#039;Stop&#039;,4=&amp;gt;&#039;Standby&#039;);; return {ChargeMode=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/global/awattar/boolAwattarEnabled:.* boolAwattarEnabled\&lt;br /&gt;
$DEVICETOPIC/global/awattar/ActualPriceForCharging:.* ActualPriceForCharging\&lt;br /&gt;
$DEVICETOPIC/global/awattar/MaxPriceForCharging:.* MaxPriceForCharging\&lt;br /&gt;
$DEVICETOPIC/global/boolRse:.* boolRse\&lt;br /&gt;
$DEVICETOPIC/global/DailyYieldAllChargePointsKwh:.* DailyYieldAllChargePointsKwh\&lt;br /&gt;
$DEVICETOPIC/global/rfidConfigured:.* rfidConfigured\&lt;br /&gt;
$DEVICETOPIC/global/kWhCounterAllChargePoints:.* kWhCounterAllChargePoints\&lt;br /&gt;
$DEVICETOPIC/global/strLastmanagementActive:.* strLastmanagementActive\&lt;br /&gt;
$DEVICETOPIC/global/ETProvider/modulePath:.* modulePath\&lt;br /&gt;
$DEVICETOPIC/global/cpuTemp:.* cpuTemp\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/system/Uptime:.* Uptime\&lt;br /&gt;
$DEVICETOPIC/system/Date:.* Date\&lt;br /&gt;
$DEVICETOPIC/system/Timestamp:.* Timestamp\&lt;br /&gt;
$DEVICETOPIC/system/Version:.* Version\&lt;br /&gt;
$DEVICETOPIC/system/IpAddress:.* IpAddress\&lt;br /&gt;
$DEVICETOPIC/system/lastRfId:.* lastRfId\&lt;br /&gt;
$DEVICETOPIC/system/updateInProgress:.* updateInProgress\&lt;br /&gt;
$DEVICETOPIC/system/ConfiguredChargePoints:.* ConfiguredChargePoints\&lt;br /&gt;
$DEVICETOPIC/system/lastlivevalues:.* lastlivevalues\&lt;br /&gt;
$DEVICETOPIC/system/randomSleep:.* randomSleep\&lt;br /&gt;
$DEVICETOPIC/system/wizzardDone:.* wizzardDone\&lt;br /&gt;
$DEVICETOPIC/system/priceForKWh:.* priceForKWh\&lt;br /&gt;
$DEVICETOPIC/system/reloadDisplay:.* reloadDisplay\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/evu/ASchieflast:.* ASchieflast\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/P%Soc:.* lp_1_Pct_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/1/%Soc:.* lp_1_current_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/1/\x25Soc:.* lp_1__Soc\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/countPhasesInUse:.* lp_1_countPhasesInUse\&lt;br /&gt;
$DEVICETOPIC/lp/1/ChargePointEnabled:.* lp_1_ChargePointEnabled\&lt;br /&gt;
$DEVICETOPIC/lp/1/ChargeStatus:.* lp_1_ChargeStatus\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhDailyCharged:.* lp_1_kWhDailyCharged\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhCounter:.* lp_1_kWhCounter\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhActualCharged:.* lp_1_kWhActualCharged\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhChargedSincePlugged:.* lp_1_kWhChargedSincePlugged\&lt;br /&gt;
$DEVICETOPIC/lp/1/energyConsumptionPer100km:.* lp_1_energyConsumptionPer100km\&lt;br /&gt;
$DEVICETOPIC/lp/1/kmCharged:.* lp_1_kmCharged\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/strChargePointName:.* lp_1_strChargePointName\&lt;br /&gt;
$DEVICETOPIC/lp/1/TimeRemaining:.* lp_1_TimeRemaining\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase2:.* lp_1_PfPhase2\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase3:.* lp_1_PfPhase3\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase1:.* lp_1_PfPhase1\&lt;br /&gt;
$DEVICETOPIC/lp/1/W:.* lp_1_W\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolPlugStat:.* {my %h=(0=&amp;gt;&#039;no Plug&#039;,1=&amp;gt;&#039;Plugged in&#039;);; return {lp_1_PlugStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargeStat:.* {my %h=(0=&amp;gt;&#039;not loading&#039;,1=&amp;gt;&#039;loading&#039;);; return {lp_1_ChargeStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/1/AConfigured:.* lp_1_AConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargePointConfigured:.* lp_1_boolChargePointConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolSocConfigured:.* lp_1_boolSocConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolDirectModeChargekWh:.* lp_1_boolDirectModeChargekWh\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolDirectChargeModeSoc:.* lp_1_boolDirectChargeModeSoc\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolFinishAtTimeChargeActive:.* lp_1_boolFinishAtTimeChargeActive\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargeAtNight:.* lp_1_boolChargeAtNight\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolSocManual:.* lp_1_boolSocManual\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/AutolockStatus:.* lp_1_AutolockStatus\&lt;br /&gt;
$DEVICETOPIC/lp/1/AutolockConfigured:.* lp_1_AutolockConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/lastRfId:.* lp_1_lastRfId\&lt;br /&gt;
$DEVICETOPIC/lp/1/pluggedladungakt:.* lp_1_pluggedladungakt\&lt;br /&gt;
$DEVICETOPIC/lp/1/plugStartkWh:.* lp_1_plugStartkWh\&lt;br /&gt;
$DEVICETOPIC/lp/1/MeterSerialNumber:.* lp_1_MeterSerialNumber\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/P%Soc:.* lp_2_Pct_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/2/%Soc:.* lp_2_current_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/2/\x25Soc:.* lp_2__Soc\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/countPhasesInUse:.* lp_2_countPhasesInUse\&lt;br /&gt;
$DEVICETOPIC/lp/2/ChargePointEnabled:.* lp_2_ChargePointEnabled\&lt;br /&gt;
$DEVICETOPIC/lp/2/ChargeStatus:.* lp_2_ChargeStatus\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhDailyCharged:.* lp_2_kWhDailyCharged\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhCounter:.* lp_2_kWhCounter\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhActualCharged:.* lp_2_kWhActualCharged\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhChargedSincePlugged:.* lp_2_kWhChargedSincePlugged\&lt;br /&gt;
$DEVICETOPIC/lp/2/energyConsumptionPer100km:.* lp_2_energyConsumptionPer100km\&lt;br /&gt;
$DEVICETOPIC/lp/2/kmCharged:.* lp_2_kmCharged\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/strChargePointName:.* lp_2_strChargePointName\&lt;br /&gt;
$DEVICETOPIC/lp/2/TimeRemaining:.* lp_2_TimeRemaining\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/W:.* lp_2_W\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolPlugStat:.* {my %h=(0=&amp;gt;&#039;no Plug&#039;,1=&amp;gt;&#039;Plugged in&#039;);; return {lp_2_PlugStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargeStat:.* {my %h=(0=&amp;gt;&#039;not loading&#039;,1=&amp;gt;&#039;loading&#039;);; return {lp_2_ChargeStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/2/AConfigured:.* lp_2_AConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargePointConfigured:.* lp_2_boolChargePointConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolSocConfigured:.* lp_2_boolSocConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolDirectModeChargekWh:.* lp_2_boolDirectModeChargekWh\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolDirectChargeModeSoc:.* lp_2_boolDirectChargeModeSoc\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolFinishAtTimeChargeActive:.* lp_2_boolFinishAtTimeChargeActive\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargeAtNight:.* lp_2_boolChargeAtNight\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolSocManual:.* lp_2_boolSocManual\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/AutolockStatus:.* lp_2_AutolockStatus\&lt;br /&gt;
$DEVICETOPIC/lp/2/AutolockConfigured:.* lp_2_AutolockConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/lastRfId:.* lp_2_lastRfId\&lt;br /&gt;
$DEVICETOPIC/lp/2/pluggedladungakt:.* lp_2_pluggedladungakt\&lt;br /&gt;
$DEVICETOPIC/lp/2/plugStartkWh:.* lp_2_plugStartkWh\&lt;br /&gt;
$DEVICETOPIC/lp/2/MeterSerialNumber:.* lp_2_MeterSerialNumber\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_direct:.* boolChargeAtNight_direct\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_nurpv:.* boolChargeAtNight_nurpv\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_minpv:.* boolChargeAtNight_minpv\&lt;br /&gt;
$DEVICETOPIC/boolDisplayHouseConsumption:.* boolDisplayHouseConsumption\&lt;br /&gt;
$DEVICETOPIC/boolDisplayDailyCharged:.* boolDisplayDailyCharged\&lt;br /&gt;
$DEVICETOPIC/boolEvuSmoothedActive:.* boolEvuSmoothedActive\&lt;br /&gt;
$DEVICETOPIC/pv/bool70PVDynActive:.* bool70PVDynActive\&lt;br /&gt;
$DEVICETOPIC/pv/W70PVDyn:.* W70PVDyn\&lt;br /&gt;
$DEVICETOPIC/pv/bool70PVDynStatus:.* bool70PVDynStatus\&lt;br /&gt;
$DEVICETOPIC/pv/CounterTillStartPvCharging:.* CounterTillStartPvCharging\&lt;br /&gt;
$DEVICETOPIC/pv/W:.* W\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/nurpv70dynact:.* nurpv70dynact\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/nurpv70dynw:.* nurpv70dynw\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/priorityModeEVBattery:.* priorityModeEVBattery\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minSocAlwaysToChargeTo:.* lp_1_minSocAlwaysToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/maxSoc:.* lp_1_maxSoc\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minSocAlwaysToChargeToCurrent:.* lp_1_minSocAlwaysToChargeToCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/maxSocToChargeTo:.* lp_1_maxSocToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minCurrent:.* lp_1_minCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/socLimitation:.* lp_1_socLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/minCurrent:.* lp_2_minCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/maxSoc:.* lp_2_maxSoc\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/socLimitation:.* lp_2_socLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/socStopChargeAtMinPv:.* socStopChargeAtMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/regulationPoint:.* regulationPoint\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minBatteryDischargeSocAtBattPriority:.* minBatteryDischargeSocAtBattPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minBatteryChargePowerAtEvPriority:.* minBatteryChargePowerAtEvPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minFeedinPowerBeforeStart:.* minFeedinPowerBeforeStart\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/boolAdaptiveCharging:.* boolAdaptiveCharging\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/adaptiveChargingFactor:.* adaptiveChargingFactor\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/batteryDischargePowerAtBattPriority:.* batteryDischargePowerAtBattPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/boolShowPriorityIconInTheme:.* boolShowPriorityIconInTheme\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/maxPowerConsumptionBeforeStop:.* maxPowerConsumptionBeforeStop\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/stopDelay:.* stopDelay\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/chargeSubmode:.* chargeSubmode\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minCurrentMinPv:.* minCurrentMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/socStartChargeAtMinPv:.* socStartChargeAtMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/startDelay:.* startDelay\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/energyToCharge:.* lp_2_energyToCharge\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/chargeLimitation:.* lp_2_chargeLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/socToChargeTo:.* lp_2_socToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/current:.* lp_2_current\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/socToChargeTo:.* lp_1_socToChargeTo\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/energyToCharge:.* lp_1_energyToCharge\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/chargeLimitation:.* lp_1_chargeLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/current:.* lp_1_current\&lt;br /&gt;
$DEVICETOPIC/config/get/global/minEVSECurrentAllowed:.* minEVSECurrentAllowed\&lt;br /&gt;
$DEVICETOPIC/config/get/global/maxEVSECurrentAllowed:.* maxEVSECurrentAllowed\&lt;br /&gt;
$DEVICETOPIC/config/get/global/dataProtectionAcknoledged:.* dataProtectionAcknoledged\&lt;br /&gt;
$DEVICETOPIC/config/get/global/slaveMode:.* slaveMode\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/standbyPhases:.* standbyPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/sofortPhases:.* sofortPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/nachtPhases:.* nachtPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/minundpvPhases:.* minundpvPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/nurpvPhases:.* nurpvPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/isConfigured:.* isConfigured\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_standby:.* boolChargeAtNight_standby\&lt;br /&gt;
$DEVICETOPIC/set/system/reloadDisplay:.* reloadDisplay\&lt;br /&gt;
$DEVICETOPIC/set/system/topicSender:.* topicSender\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/faultState:.* lp_2_faultState\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/faultStr:.* lp_2_faultStr\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/ChargePointEnabled:.* lp_2_ChargePointEnabled&lt;br /&gt;
attr WB_1 room MQTT2_DEVICE,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WB_1 setList Lademodus:SofortLaden,Min+PV,NurPV,Stop,Standby { my %h=(SofortLaden=&amp;gt;&#039;0&#039;,&#039;Min+PV&#039;=&amp;gt;&#039;1&#039;,NurPV=&amp;gt;&#039;2&#039;,Stop=&amp;gt;&#039;3&#039;,Standby=&amp;gt;&#039;4&#039;);;qq($DEVICETOPIC/set/ChargeMode $h{$EVTPART1}) }\&lt;br /&gt;
DirectChargeSubMode:Aus,kWh_Laden,SoC_Laden { my %h=(Aus=&amp;gt;&#039;0&#039;,kWh_Laden=&amp;gt;&#039;1&#039;,SoC_Laden=&amp;gt;&#039;2&#039;);;qq($DEVICETOPIC/set/lp1/DirectChargeSubMode $h{$EVTPART1}) }\&lt;br /&gt;
lp_1_socToChargeTo:50,60,70,80,90,100 { qq($DEVICETOPIC/config/set/sofort/lp/1/socToChargeTo $EVTPART1) }&lt;br /&gt;
attr WB_1 sortby 311&lt;br /&gt;
attr WB_1 stateFormat {\&lt;br /&gt;
 my $YearBefore=&#039;LogDBRep_Statistic_previous_Year&#039;;;\&lt;br /&gt;
 my $DUMMY  = &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $date = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;lastlivevalues&amp;quot;,0))));;\&lt;br /&gt;
\&lt;br /&gt;
 my $ChargeMode          = ReadingsVal($name,&amp;quot;ChargeMode&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
    $ChargeMode          = ($ChargeMode eq &amp;quot;SofortLaden&amp;quot;)? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;SofortLaden&amp;lt;/span&amp;gt;&amp;quot; : ($ChargeMode eq &amp;quot;MinPV&amp;quot;)?  &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Min+PV&amp;lt;/span&amp;gt;&amp;quot; : ($ChargeMode eq &amp;quot;NurPV&amp;quot;)?  &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;NurPV&amp;lt;/span&amp;gt;&amp;quot; : $ChargeMode;;\&lt;br /&gt;
 \&lt;br /&gt;
 my $lp_1_Name           = ReadingsVal($name,&amp;quot;lp_1_strChargePointName&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_1_Power          = ReadingsVal($name,&amp;quot;lp_1_W&amp;quot;,0).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_1        = ReadingsVal($name,&amp;quot;lp_1_countPhasesInUse&amp;quot;,0).&amp;quot;P &amp;quot;.ReadingsVal($name,&amp;quot;lp_1_AConfigured&amp;quot;,0).&amp;quot;A&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Status_1       = ReadingsVal($name,&amp;quot;lp_1_PlugStat&amp;quot;,&amp;quot;n/a&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_1_ChargeStat&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_1_Status_2       = ReadingsVal($name,&amp;quot;lp_1_TimeRemaining&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_1_Power_d        = ReadingsVal($name,&amp;quot;lp_1_kWhDailyCharged&amp;quot;,0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_m        = round(ReadingsVal($name,&amp;quot;lp_1_kWhCounter_Month&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_j        = sprintf(&amp;quot;%04d / %04d&amp;quot;,ReadingsVal($name,&amp;quot;lp_1_kWhCounter_Year&amp;quot;,0),ReadingsVal($YearBefore,&amp;quot;lp_1_kWhCounter_Year&amp;quot;,0));;\&lt;br /&gt;
 my $lp_1_Power_t        = round(ReadingsVal($name,&amp;quot;lp_1_kWhCounter&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_2_Name           = ReadingsVal($name,&amp;quot;lp_2_strChargePointName&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_2_Power          = ReadingsVal($name,&amp;quot;lp_2_W&amp;quot;,0).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_1        = ReadingsVal($name,&amp;quot;lp_2_countPhasesInUse&amp;quot;,0).&amp;quot;P &amp;quot;.ReadingsVal($name,&amp;quot;lp_2_AConfigured&amp;quot;,0).&amp;quot;A&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Status_1       = ReadingsVal($name,&amp;quot;lp_2_PlugStat&amp;quot;,&amp;quot;n/a&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_2_ChargeStat&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_2_Status_2       = &amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_2_TimeRemaining&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_2_Power_d        = ReadingsVal($name,&amp;quot;lp_2_kWhDailyCharged&amp;quot;,0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_m        = round(ReadingsVal($name,&amp;quot;lp_2_kWhCounter_Month&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_j        = sprintf(&amp;quot;%04d / %04d&amp;quot;,ReadingsVal($name,&amp;quot;lp_2_kWhCounter_Year&amp;quot;,0),ReadingsVal($YearBefore,&amp;quot;lp_2_kWhCounter_Year&amp;quot;,0));;\&lt;br /&gt;
 my $lp_2_Power_t        = round(ReadingsVal($name,&amp;quot;lp_2_kWhCounter&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Wallbox&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;$ChargeMode&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Status&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;Restladezeit&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;Leistung&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_1_Name.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Status_1.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Status_2.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_1.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$lp_1_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_2_Name.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Status_1.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Status_2.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_1.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$lp_2_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Statistik vom $date&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;aktuell&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Jahr/Vorjahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_1_Name.&amp;quot;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_d.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_m.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_j.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_2_Name.&amp;quot;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_d.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_m.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_j.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr WB_1 userReadings lp_1_kWhCounter_Month:lp_1_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter_init_Month&amp;quot;,0),0) },\&lt;br /&gt;
lp_1_kWhCounter_Year:lp_1_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter_init_Year&amp;quot;,0),0)  },\&lt;br /&gt;
\&lt;br /&gt;
lp_2_kWhCounter_Month:lp_2_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter_init_Month&amp;quot;,0),0) },\&lt;br /&gt;
lp_2_kWhCounter_Year:lp_2_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter_init_Year&amp;quot;,0),0)  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia connect MQTT=====&lt;br /&gt;
Das Kia_connect Device empfängt und sendet die MQTT Nachrichten zum Node-red Flow für das Kia BEV.&lt;br /&gt;
&lt;br /&gt;
RAW des Kia connect&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Kia_connect MQTT2_DEVICE&lt;br /&gt;
attr Kia_connect DbLogExclude .*&lt;br /&gt;
attr Kia_connect DbLogInclude .*&lt;br /&gt;
attr Kia_connect IODev MQTT2_FHEM_Server&lt;br /&gt;
attr Kia_connect alias Kia_connect&lt;br /&gt;
attr Kia_connect autocreate 1&lt;br /&gt;
attr Kia_connect devicetopic bluelinky&lt;br /&gt;
attr Kia_connect group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Kia_connect icon car&lt;br /&gt;
attr Kia_connect readingList $DEVICETOPIC/status:.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/location.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/odometer:.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/req_received:.* req_received\&lt;br /&gt;
$DEVICETOPIC/req_active:.* req_active&lt;br /&gt;
attr Kia_connect room MQTT2_DEVICE,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Kia_connect setList getOdometer req/$DEVICETOPIC/get_odometer get_odometer\&lt;br /&gt;
getStatus req/$DEVICETOPIC/get_status get_status\&lt;br /&gt;
getLocation req/$DEVICETOPIC/get_location get_location\&lt;br /&gt;
getTripinfo req/$DEVICETOPIC/get_tripinfo\&lt;br /&gt;
getAll req/$DEVICETOPIC/get_all get_all\&lt;br /&gt;
setChargeTargetSoc req/$DEVICETOPIC/set_chargetargets\&lt;br /&gt;
startCharge req/$DEVICETOPIC/start_charging start_charging\&lt;br /&gt;
stopCharge req/$DEVICETOPIC/stop_charging stop_charging\&lt;br /&gt;
stopClimate req/$DEVICETOPIC/stop_climate stop_climate\&lt;br /&gt;
startClimate req/$DEVICETOPIC/start_climate&lt;br /&gt;
attr Kia_connect sortby 402&lt;br /&gt;
attr Kia_connect stateFormat req_active&lt;br /&gt;
attr Kia_connect userReadings atHomeStanding:location.* { ((abs(AttrVal(&amp;quot;global&amp;quot;,&amp;quot;latitude&amp;quot;,49.85) - ReadingsVal($NAME,&amp;quot;location_coord_lat&amp;quot;,0)) &amp;lt;= 0.001) &amp;amp;&amp;amp; (abs(AttrVal(&amp;quot;global&amp;quot;,&amp;quot;longitude&amp;quot;,8.49) - ReadingsVal($NAME,&amp;quot;location_coord_lon&amp;quot;,0)) &amp;lt;= 0.001) &amp;amp;&amp;amp; (ReadingsVal($NAME,&amp;quot;location_speed_value&amp;quot;,1) == 0)) ? &#039;true&#039; : &#039;false&#039;;;;; },\&lt;br /&gt;
batSOC:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_batteryStatus&amp;quot;,0);;;;},\&lt;br /&gt;
connected:status.* { (ReadingsVal($NAME,&amp;quot;status_evStatus_batteryPlugin&amp;quot;,0) != 0) ? &#039;true&#039; : &#039;false&#039;;;;;},\&lt;br /&gt;
charging:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_batteryCharge&amp;quot;,&#039;false&#039;);;;;},\&lt;br /&gt;
targetSOC:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel&amp;quot;,0);;;;},\&lt;br /&gt;
time2targetSOC:status.* { my $t = ReadingsVal($NAME,&amp;quot;status_evStatus_remainTime2_atc_value&amp;quot;,1);;;; sprintf(&amp;quot;%02d:%02d&amp;quot;, $t/60%60, $t%60);;},\&lt;br /&gt;
range:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_drvDistance_1_rangeByFuel_totalAvailableRange_value&amp;quot;,0);;;;},\&lt;br /&gt;
bat12v:status.* { ReadingsVal($NAME,&amp;quot;status_battery_batSoc&amp;quot;,0);;;;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Node-red=====&lt;br /&gt;
[[Bild:Kia Flow.PNG|mini|900px|rechts|Node-red Kia Flow]]&lt;br /&gt;
Node-red habe ich einfach in einem Docker Container runter geladen und gestartet. Über Port 1880 kommt man direkt in die GUI und kann den ersten Flow laden.&lt;br /&gt;
&lt;br /&gt;
docker-compose .yml Eintrag&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
  node-red:&lt;br /&gt;
    image: nodered/node-red:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
    environment:&lt;br /&gt;
      - TZ=Europe/Berlin&lt;br /&gt;
    ports:&lt;br /&gt;
      - 1880:1880&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./node-red/data:/data&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Danach fehlt im Container noch folgende Erweiterung für den Node-red Flow&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
npm install node-red-contrib-bluelinky&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Node-red Kia Flow muss für MQTT dann noch der Benutzer und das Passwort abgelegt werden. Ansonst kommt nämlich im FHEM nichts an.&lt;br /&gt;
&lt;br /&gt;
=====Kia Connect=====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Kia connect ist eine API für Kia und Hyundai E-Autos mit der man Daten vom Auto abfragen kann und auch einige Steuerungen möglich sind.&lt;br /&gt;
Mit Node-red und BlueLinky wird die Schnittstelle bedient.&lt;br /&gt;
Der Flow ist nicht ursprünglich von mir, wurde jedoch noch erweitert.&lt;br /&gt;
Vor dem Laden des Flows sind noch die persönlichen Verbindungsdaten im JSON einzutragen.&lt;br /&gt;
&lt;br /&gt;
Nach dem Laden ist ein Test mit den Inject Symbolen und der Debug Funktionalität möglich und auch sinnvoll.&lt;br /&gt;
Unterhalb der MQTT - und BlueLinky Symbole sollte &amp;quot;Verbunden&amp;quot; oder &amp;quot;Ready&amp;quot; erscheinen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wichtig beim Kia ist, dass für das Laden über die openWB als SOC Ziel 80% im standard Modus konfiguriert wird.&#039;&#039;&#039; Ansonsten wundert man sich warum das Laden einfach nicht starten möchte. Im Default ist dort bei mir nur 50% eingetragen gewesen :-). Mit jetzt 100% kann die openWB auch selber einen Ziel SOC bestimmen, ansonsten hört das BEV einfach selber auf zu laden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin sollte man darauf achten, dass man nur eine begrenzte Anzahl von Nachrichten mit dem Kia BEV pro Tag austauschen kann. Das wurde im DOIF schon etwas berücksichtigt (1x pro Stunde), kann jedoch bei gleichzeitiger Verwendung der Handy App oder der SOC Abfrage im openWB Kia Modul auch mal zu Fehlern führen. Durch die Stündliche Status Abfrage im DOIF kommt es natürlich zu Verzögerungen im FHEM Status. Dann einfach einmal Manuell abfragen.&lt;br /&gt;
&lt;br /&gt;
Node-red JSON Import&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
[    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;tab&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Kia e-Niro&amp;quot;,&lt;br /&gt;
        &amp;quot;disabled&amp;quot;: false,&lt;br /&gt;
        &amp;quot;info&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt-broker&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;mqtt_Server&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;&amp;lt;FHEM MQTT IP Adresse&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;port&amp;quot;: &amp;quot;1883&amp;quot;,&lt;br /&gt;
        &amp;quot;clientid&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;autoConnect&amp;quot;: true,&lt;br /&gt;
        &amp;quot;usetls&amp;quot;: false,&lt;br /&gt;
        &amp;quot;compatmode&amp;quot;: false,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;: &amp;quot;4&amp;quot;,&lt;br /&gt;
        &amp;quot;keepalive&amp;quot;: &amp;quot;60&amp;quot;,&lt;br /&gt;
        &amp;quot;cleansession&amp;quot;: true,&lt;br /&gt;
        &amp;quot;birthTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;birthQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;birthPayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;birthMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;closeTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;closeQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;closePayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;closeMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;willTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;willQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;willPayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;willMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;sessionExpiry&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;bluelinky&amp;quot;,&lt;br /&gt;
        &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Mail Adresse bei Kia&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Passwort&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;region&amp;quot;: &amp;quot;EU&amp;quot;,&lt;br /&gt;
        &amp;quot;pin&amp;quot;: &amp;quot;&amp;lt;Pin&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;vin&amp;quot;: &amp;quot;&amp;lt;VIN&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;brand&amp;quot;: &amp;quot;kia&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;91a345fa.5757a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_status&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;15dfb508.c6497b&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5ad085b9.05739c&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/start_climate&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;b27d74de.38c808&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;15dfb508.c6497b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-status&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get status&amp;quot;,&lt;br /&gt;
        &amp;quot;dorefresh&amp;quot;: true,&lt;br /&gt;
        &amp;quot;parsed&amp;quot;: false,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;cccc9476.d56dd8&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;87abdd88.8ff4d&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get car odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;40d2361c.579588&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;31100f9a.40008&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;locationWrapper&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;location\&amp;quot;: msg.payload,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;libs&amp;quot;: [],&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1490,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;bea1d927.0f3908&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-location&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get car location&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;31100f9a.40008&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3c949d67.0d83b2&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_location&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;bea1d927.0f3908&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;cccc9476.d56dd8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;analyseStatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    let status = msg.payload;\n    status.airTemp.value = 14+(parseInt(status.airTemp.value,16)/2);\n    try{\n    status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    } catch(e) {}\n\n    let time = status.evStatus.remainTime2.atc.value/60;\n    let result = { \n                 \&amp;quot;batSOC\&amp;quot;: status.evStatus.batteryStatus,\n                 \&amp;quot;connected\&amp;quot;: (status.evStatus.batteryPlugin !== 0),\n                 \&amp;quot;charging\&amp;quot;: status.evStatus.batteryCharge,\n                 \&amp;quot;targetSOC\&amp;quot;: status.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,\n                 \&amp;quot;time2targetSOC\&amp;quot;: (Math.floor(time) + \&amp;quot;:\&amp;quot; + (\&amp;quot;0\&amp;quot; + Math.floor((time % 1)*60)).slice(-2)), // h:mm\n                 \&amp;quot;range\&amp;quot;: status.evStatus.drvDistance[0].rangeByFuel.totalAvailableRange.value,\n                 \&amp;quot;bat12v\&amp;quot;: status.battery.batSoc\n                };\n    \n    //msg.payload = result;\n    msg.payload = {\n        \&amp;quot;status\&amp;quot;: status,\n        \&amp;quot;error\&amp;quot;: false\n        \n    };\n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1480,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/location&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/status&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1900,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;844a32f4.2e029&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/stop_climate&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7d3ae860.d8c9a8&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;57d91e50.7e96&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/start_charging&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 820,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;6eebc52c.ee23dc&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;6029f0a0.b73e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/stop_charging&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 880,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;84a1ae.74912e5&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;c5ecf76c.e753c8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;start-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Start car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;6eebc52c.ee23dc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;start-charge&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Start Charging&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 820,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;84a1ae.74912e5&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;stop-charge&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Stop Charging&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 880,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7d3ae860.d8c9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;stop-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Stop car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;b27d74de.38c808&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;obj&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;c5ecf76c.e753c8&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;45a6a8e6.2abfd8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;87abdd88.8ff4d&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 930,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 920,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/req_received&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 860,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 480,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;1babee6c.1c2982&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_all&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;,&lt;br /&gt;
                &amp;quot;4375fbb9.00fb44&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1850,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1470,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 930,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;24d5e0b.3aafc2&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;change&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;rules&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;t&amp;quot;: &amp;quot;set&amp;quot;,&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
                &amp;quot;pt&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
                &amp;quot;to&amp;quot;: &amp;quot;pending&amp;quot;,&lt;br /&gt;
                &amp;quot;tot&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;from&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;to&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;reg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 790,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1140,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
                &amp;quot;fecad185.324f8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;change&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;rules&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;t&amp;quot;: &amp;quot;set&amp;quot;,&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
                &amp;quot;pt&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
                &amp;quot;to&amp;quot;: &amp;quot;idle&amp;quot;,&lt;br /&gt;
                &amp;quot;tot&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;from&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;to&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;reg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
                &amp;quot;fecad185.324f8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/req_active&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 2140,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;fecad185.324f8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;false&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 2110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1160,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;40d2361c.579588&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;odometerWrapper&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    msg.payload = { \n        \&amp;quot;odometer\&amp;quot;: msg.payload,\n        \&amp;quot;error\&amp;quot;: false\n        };\n\n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;libs&amp;quot;: [],&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1490,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;226ed925.607bb6&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1430,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4375fbb9.00fb44&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-fullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get full status&amp;quot;,&lt;br /&gt;
        &amp;quot;dorefresh&amp;quot;: true,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;,&lt;br /&gt;
                &amp;quot;69b6c4df.ea6bcc&amp;quot;,&lt;br /&gt;
                &amp;quot;89681a97.9e24d8&amp;quot;,&lt;br /&gt;
                &amp;quot;92dc3ff4.1d6e3&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;69b6c4df.ea6bcc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;locationFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;location\&amp;quot;: msg.payload.vehicleLocation,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1500,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;92dc3ff4.1d6e3&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;statusFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    let status = msg.payload.vehicleStatus;\n    try{\n        status.airTemp.value = 14+(parseInt(status.airTemp.value,16)/2);\n        status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n        status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    } catch(e) {}\n\n    msg.payload = { \n        \&amp;quot;status\&amp;quot;: status,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1500,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 480,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;89681a97.9e24d8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;odometerFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;odometer\&amp;quot;: msg.payload.odometer,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1510,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 420,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;331e5860.907808&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1850,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 520,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;aa4d220b.f7e19&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;set-chargetargets&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Set charge targets&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4c03338d.2f15ec&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;login&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Login&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1090,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;28b868f5.16cb48&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;43200&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: true,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: &amp;quot;12&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 950,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4c03338d.2f15ec&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;db9ecdb5.a9683&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/set_chargetargets&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 290,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7064a8d53256b646&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;44155ad70c47b0dd&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;15dfb508.c6497b&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7064a8d53256b646&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;obj&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;aa4d220b.f7e19&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7064395e56292844&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 340,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4375fbb9.00fb44&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5f9ff828080f5fe6&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;lock-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Lock car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 560,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;492f5b94a865e47b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 540,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;5f9ff828080f5fe6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;d6f3f148e765caf9&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/car_lock&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 560,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;5f9ff828080f5fe6&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;cdc13a486db22b8e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/car_unlock&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 620,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;99f5c3a41ac3e754&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;99f5c3a41ac3e754&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unlock-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Unlock car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 620,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ab557a0ea621403a&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 600,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;99f5c3a41ac3e754&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;a525de86e4374518&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 740,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7d3ae860.d8c9a8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;0b8cb92c042fe140&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 800,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;6eebc52c.ee23dc&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ae4c2139b08aaa28&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 860,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;84a1ae.74912e5&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;dd23108ce63f456d&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;get-monthlyreport&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get monthly report&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;e57eb97531129426&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;a6e5e8deb52145f1&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1260,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;dd23108ce63f456d&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;95f1b6f32aafd65b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;get-tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;e57eb97531129426&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;fb2b99958bc48593&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;95f1b6f32aafd65b&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5230ebe391325b17&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: true,&lt;br /&gt;
        &amp;quot;rh&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;fb2b99958bc48593&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;e57eb97531129426&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1470,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4fdf3b1b7811c89f&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: true,&lt;br /&gt;
        &amp;quot;rh&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;dd23108ce63f456d&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia_eNiro_PV DOIF mit uiTable=====&lt;br /&gt;
Mit diesem DOIF Device werden folgende Funktionalitäten abgebildet:&lt;br /&gt;
Nun dann noch das DOIF mit dem uiTable für die Status Anzeige und die Steuerung über Pull Down Menüs.&lt;br /&gt;
&lt;br /&gt;
- Status Abfrage&lt;br /&gt;
     Status jede Stunde zwischen 6 und 23 Uhr (12V min 40%)&lt;br /&gt;
     Status beim Laden alle 15 Minuten (12V min 40%)&lt;br /&gt;
     Anzeige des Kilometerzählers&lt;br /&gt;
     Status des Fahrzeuges zu Hause / unterwegs und beim Laden&lt;br /&gt;
     Fahrzeug Auf/Zu&lt;br /&gt;
&lt;br /&gt;
- Klimatisierung über das Pull Down Menü&lt;br /&gt;
     unterschiedliche Temperaturen für Heizen und Kühlen&lt;br /&gt;
     Aktuelle Temperatur&lt;br /&gt;
     Heizen/Klima Ein/Aus&lt;br /&gt;
     Timer für zeitgesteuertes Klimatisieren für den Resttag oder den Nächsten Tag (vor der aktuellen Zeit)&lt;br /&gt;
     Klimatisierung über &amp;quot;Abfall&amp;quot; Kalender (es geht nur ein Termin pro Tag, dafür aber komfortabel über das Handy)&lt;br /&gt;
&lt;br /&gt;
- Komfort&lt;br /&gt;
     Reifen Überwachung&lt;br /&gt;
     Türen / Motorhaube / Kofferraum Überwachung&lt;br /&gt;
     12V Batterie anzeige, wenn der Ladezustand kleiner 40% ist erfolgt keine weitere Status Abfrage&lt;br /&gt;
&lt;br /&gt;
- ACCU Steuerung&lt;br /&gt;
    Setzen des Ziel SOC beim Standard Laden&lt;br /&gt;
    Start/Stop Laden&lt;br /&gt;
    Accu Stand und berechnete Restkilometer&lt;br /&gt;
&lt;br /&gt;
- Für openWB integratin im uiTable&lt;br /&gt;
    Wählen des Lademodus&lt;br /&gt;
    Vorrang EV oder Bat&lt;br /&gt;
    Sperren des Hausspeichers entweder manuell oder automatisch beim Laden. Der vorherige Zustand wird gespeichert&lt;br /&gt;
        Die Freigabe erfolgt über die Wechselrichter Implementierung, siehe dort [[Kostal_Plenticore_10_Plus#Externe_Speichersteuerung_.28ExternControl.29|&amp;quot;Externe Speicher Steuerung&amp;quot;]]&lt;br /&gt;
    Geschätzte Ladezeit&lt;br /&gt;
    Status Ladepunkt (Plug und Laden)&lt;br /&gt;
    Lade Status Phasen und Leistung   &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, die Kia connect Abfragen sind auf ca. 200 pro Tag von Kia limitiert! Durch die Stündliche Status Abfrage im DOIF kommt es natürlich zu Verzögerungen im FHEM Status. Dann einfach einmal manuell abfragen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Kommunikation zum Kia BEV ist manchmal sehr träge, z.B. kann eine Status Abfrage auch mal 3 Minuten dauern, deshalb wurde eine Verriegelung implementiert. Es wird ein Status pending/idle angezeigt. Nur wenn der Zustand &amp;quot;idel&amp;quot; ist, können weitere Abfragen gestartet werden. Läuft z.B. die Status Abfrage kann man ein weiteres Kommando anstarten, es wird jedoch erst abgesetzt, wenn das vorherige Kommando fertig ist. Solange bleibt im Pull Down Menü das neue Kommando stehen.&lt;br /&gt;
&lt;br /&gt;
RAW des DOIF&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Kia_eNiro_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Kia Connect Status Abfrage erfolgt mit MQTT2 ==&amp;gt; node-ret ==&amp;gt; Kia Connect\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_getAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (  ([+00:15] and                                                  ## alle 15 Minuten\&lt;br /&gt;
         [Kia_connect:atHomeStanding] eq &amp;quot;true&amp;quot; and                    ##   wenn das Auto zuhause ist\&lt;br /&gt;
         [Kia_connect:charging]       eq &amp;quot;true&amp;quot; or                     ##   und es geladen wird\&lt;br /&gt;
         [:58] and [05:00-23:00]                                       ## ansonsten nur jede Stunde\&lt;br /&gt;
        ) and [Kia_connect:bat12v] &amp;gt; 40                                ## aber die 12V Batterie sollte noch genügend Ladung haben\&lt;br /&gt;
      or [$SELF:cmd_event]  eq &amp;quot;set_cmd_1&amp;quot;                             ## Das reagiert auf den Aufruf mit &amp;quot;set &amp;lt;Device&amp;gt; cmd_*&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_getAll&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_getAll&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_before_1&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    fhem_set(&amp;quot;Kia_connect getAll&amp;quot;);;                                    ## beliebige Kommandos für diesen Block\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_Klima\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_2] eq &amp;quot;stopClimate&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;startHeating&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;startCooling&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_2&amp;quot;,[$SELF:ui_command_2]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;startHeating&amp;quot;) {\&lt;br /&gt;
      my $airTemp_value= [Kia_connect:status_airTemp_value_target_Winter];;\&lt;br /&gt;
      fhem_set(&#039;Kia_connect startClimate {&amp;quot;defrost&amp;quot;: true, &amp;quot;windscreenHeating&amp;quot;: true, &amp;quot;temperature&amp;quot;: &#039;.$airTemp_value.&#039; , &amp;quot;unit&amp;quot;: &amp;quot;C&amp;quot;}&#039;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : startHeating&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;startCooling&amp;quot;) {\&lt;br /&gt;
      my $airTemp_value = [Kia_connect:status_airTemp_value_target_Summer];;\&lt;br /&gt;
      fhem_set(&#039;Kia_connect startClimate {&amp;quot;defrost&amp;quot;: false, &amp;quot;windscreenHeating&amp;quot;: false, &amp;quot;temperature&amp;quot;: &#039;.$airTemp_value.&#039; , &amp;quot;unit&amp;quot;: &amp;quot;C&amp;quot;}&#039;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : startCooling&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;stopClimate&amp;quot;) {\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_2]);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : stopClimate&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    fhem_set(&amp;quot;Abfall update&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_Laden\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_3] eq &amp;quot;setChargeTargetSoc&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_3] eq &amp;quot;startCharge&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_3] eq &amp;quot;stopCharge&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_3&amp;quot;,[$SELF:ui_command_3]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_3] eq &amp;quot;setChargeTargetSoc&amp;quot;) {\&lt;br /&gt;
      my $targetSOClist_1_targetSOClevel = [Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_1_targetSOClevel_target];;\&lt;br /&gt;
      my $targetSOClist_2_targetSOClevel = [Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel_target];;\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect setChargeTargetSoc {\&amp;quot;fast\&amp;quot;: &amp;quot;.$targetSOClist_1_targetSOClevel.&amp;quot;, \&amp;quot;slow\&amp;quot;: &amp;quot;.$targetSOClist_2_targetSOClevel.&amp;quot;}&amp;quot;);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_3]);;                   ## beliebige Kommandos für diesen Block\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_3&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
4_Klima_timer_heizen\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       (    [[Abfall_Abfuhr:Kiaheizen_connect_time]]                   ## Prüfe den Kalender Eintrag\&lt;br /&gt;
        and [Abfall_Abfuhr:Kiaheizen_connect_date] eq $ymd             ##   ist es heute?\&lt;br /&gt;
       )\&lt;br /&gt;
       or\&lt;br /&gt;
       (    [$SELF:ui_timer_mode] eq &amp;quot;heizen&amp;quot;                          ## Timer zum Heizen aktiv?\&lt;br /&gt;
        and [[$SELF:ui_timer_Start]]                                   ##   ist es soweit?\&lt;br /&gt;
       )\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 4_Klima_timer : startHeating&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_timer_mode&amp;quot;,&amp;quot;Aus&amp;quot;);;                                ## Schalte die Timer Funktion ab\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;startHeating&amp;quot;);;                        ## Es soll geheizt werden\&lt;br /&gt;
    fhem_set(&amp;quot;$SELF 2_Klima&amp;quot;);;                                         ## Aktiviere das Heizen\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
5_Klima_timer_kuehlen\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       (    [[Abfall_Abfuhr:Kiakuehlen_connect_time]]                  ## Prüfe den Kalender Eintrag\&lt;br /&gt;
        and [Abfall_Abfuhr:Kiakuehlen_connect_date] eq $ymd            ##   ist es heute?\&lt;br /&gt;
       )\&lt;br /&gt;
       or\&lt;br /&gt;
       (    [$SELF:ui_timer_mode] eq &amp;quot;kuehlen&amp;quot;                         ## Timer zum Kühler aktiv?\&lt;br /&gt;
        and [[$SELF:ui_timer_Start]]                                   ##   ist es soweit?\&lt;br /&gt;
       )\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 4_Klima_timer : startCooling&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_timer_mode&amp;quot;,&amp;quot;Aus&amp;quot;);;                                ## Schalte die Timer Funktion ab\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;startCooling&amp;quot;);;                        ## Es soll gekühlt werden\&lt;br /&gt;
    fhem_set(&amp;quot;$SELF 2_Klima&amp;quot;);;                                         ## Aktiviere das Kühlen\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
6_Auf_Zu\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_2] eq &amp;quot;car_lock&amp;quot;                            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;car_unlock&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_2&amp;quot;,[$SELF:ui_command_2]);;\&lt;br /&gt;
\&lt;br /&gt;
    fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_2]);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 6_Auf_Zu      : &amp;quot;.[$SELF:ui_command_2]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
7_WB_1_lp_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_4] eq &amp;quot;SofortLaden&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Min+PV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;NurPV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Stop&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Standby&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Vorrang_Bat&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_4&amp;quot;,[$SELF:ui_command_4]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_4] eq &amp;quot;Vorrang_Bat&amp;quot; or [$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;) {\&lt;br /&gt;
      if ([$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;) {\&lt;br /&gt;
        fhem_set(&amp;quot;WB_1 priorityModeEVBattery 1&amp;quot;);;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem_set(&amp;quot;WB_1 priorityModeEVBattery 0&amp;quot;);;\&lt;br /&gt;
      }\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 7_WB_1_lp_1    : &amp;quot;.[$SELF:ui_command_4]};;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      fhem_set(&amp;quot;WB_1 Lademodus &amp;quot;.[$SELF:ui_command_4]);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 7_WB_1_lp_1    : Lademodus &amp;quot;.[$SELF:ui_command_4]};;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_4&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
8_Speicher_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_4]   eq &amp;quot;Hausspeicher_Sperren&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot; and\&lt;br /&gt;
         [WB_1:lp_1_PlugStat]   eq &amp;quot;Plugged in&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_4&amp;quot;,[$SELF:ui_command_4]);;\&lt;br /&gt;
\&lt;br /&gt;
    if([$SELF:WR_1_Speicher_1_ExternControl_smart_laden_before] eq &amp;quot;---&amp;quot;) {\&lt;br /&gt;
\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        set_Reading(&amp;quot;WR_1_Speicher_1_ExternControl_smart_laden_before&amp;quot;,&amp;quot;aktiv&amp;quot;);;\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        set_Reading(&amp;quot;WR_1_Speicher_1_ExternControl_smart_laden_before&amp;quot;,&amp;quot;inaktiv&amp;quot;);;\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      fhem_set(&amp;quot;WR_1_Speicher_1_ExternControl cmd_2&amp;quot;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_Laden startet&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_4&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
9_WB_1_Zaehler_Statistiken\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;) and                                     ## DOIF enabled\&lt;br /&gt;
     [00:01]\&lt;br /&gt;
   ) {\&lt;br /&gt;
    fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Day &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
    fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Day &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Month &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Month &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Year &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Year &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Kia_eNiro_PV DbLogExclude .*&lt;br /&gt;
attr Kia_eNiro_PV disable 0&lt;br /&gt;
attr Kia_eNiro_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Kia_eNiro_PV icon car&lt;br /&gt;
attr Kia_eNiro_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Kia_eNiro_PV sortby 401&lt;br /&gt;
attr Kia_eNiro_PV uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status_Laden {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $charge = (::ReadingsVal($car,&amp;quot;charging&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
   my $athome = (::ReadingsVal($car,&amp;quot;atHomeStanding&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
   my $chargeathome = ($charge &amp;amp;&amp;amp; $athome);;\&lt;br /&gt;
   my $connectedathome = ($athome &amp;amp;&amp;amp; ::ReadingsVal($car,&amp;quot;connected&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   my $ret = ($chargeathome ? &amp;quot;lädt zu Hause&amp;quot; : ($connectedathome ? &amp;quot;angeschlossen zu Hause&amp;quot; : ($athome ? &amp;quot;zu Hause&amp;quot; : ($charge ? &amp;quot;Lädt auswärts&amp;quot; : &amp;quot;unterwegs&amp;quot;))));;\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_tire {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $ret = &#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Reifendruck okay&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampAll&amp;quot;,&amp;quot;1&amp;quot;) != 0) {\&lt;br /&gt;
     my $VL = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampFL&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $HL = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampRL&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $VR = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampFR&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $HR = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampRR&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     $ret = &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Reifen Störung&amp;lt;br&amp;gt;&#039;;;\&lt;br /&gt;
     if ($VL == 1){$ret.=&#039; /VL&#039;};;\&lt;br /&gt;
     if ($VR == 1){$ret.=&#039; /VR&#039;};;\&lt;br /&gt;
     if ($HL == 1){$ret.=&#039; /HL&#039;};;\&lt;br /&gt;
     if ($HR == 1){$ret.=&#039; /HR&#039;};;\&lt;br /&gt;
     $ret = $ret.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_door {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $ret = &#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Türen okay&amp;lt;br&amp;gt;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_doorLock&amp;quot;,&amp;quot;false&amp;quot;) ne &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     my $VL = (::ReadingsVal($car,&amp;quot;status_doorOpen_frontLeft&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $HL = (::ReadingsVal($car,&amp;quot;status_doorOpen_backLeft&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $VR = (::ReadingsVal($car,&amp;quot;status_doorOpen_frontRight&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $HR = (::ReadingsVal($car,&amp;quot;status_doorOpen_backRight&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     $ret = &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Tür offen&amp;lt;br&amp;gt;&#039;;;\&lt;br /&gt;
     if ($VL == 1){$ret.=&#039; /VL&#039;};;\&lt;br /&gt;
     if ($VR == 1){$ret.=&#039; /VR&#039;};;\&lt;br /&gt;
     if ($HL == 1){$ret.=&#039; /HL&#039;};;\&lt;br /&gt;
     if ($HR == 1){$ret.=&#039; /HR&#039;};;\&lt;br /&gt;
     $ret = $ret.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_trunkOpen&amp;quot;,&amp;quot;true&amp;quot;) eq &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     $ret.=&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt; Kofferraum offen&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_hoodOpen&amp;quot;,&amp;quot;true&amp;quot;) eq &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     $ret.=&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt; Motorhaube offen&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando &amp;quot;.::ReadingsTimestamp(&amp;quot;Kia_connect&amp;quot;,&amp;quot;status_time&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Auswahl / Kommunikation / Tacho / Info Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_getAll,car_lock,car_unlock&amp;quot;)|(([Kia_connect:req_active] eq &amp;quot;idle&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;idle&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;.[Kia_connect:req_active].&#039;&amp;lt;/span&amp;gt;&#039;) |::round([Kia_connect:odometer_value],0).&amp;quot; km&amp;quot;|FUNC_Status_Laden(&amp;quot;Kia_connect&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Accu&amp;lt;dd&amp;gt;Steuerung / Target Soc / Accu Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_3],&amp;quot;uzsuDropDown,---,setChargeTargetSoc,stopCharge,startCharge&amp;quot;)|&amp;quot;Target SOC&amp;quot;.widget([Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel_target],&amp;quot;selectnumbers,50,10,100,0,lin&amp;quot;).&amp;quot; %&amp;quot;|&amp;quot;&amp;quot;| FUNC_Status([Kia_connect:range],150,&amp;quot;red&amp;quot;,[Kia_connect:range],&amp;quot;orange&amp;quot;,[Kia_connect:range],250,&amp;quot;green&amp;quot;,[Kia_connect:range]).&amp;quot; km&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([Kia_connect:batSOC])).STY(::round([Kia_connect:batSOC],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Komfort&amp;lt;dd&amp;gt;Timer / Klima / Reifen / Türen / Accu Status 12V&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_timer_mode],&amp;quot;uzsuDropDown,Aus,heizen,kuehlen&amp;quot;).widget([$SELF:ui_timer_Start],&amp;quot;time&amp;quot;)|\&lt;br /&gt;
((::ReadingsVal(&amp;quot;Abfall_Abfuhr&amp;quot;,&amp;quot;Kiaheizen_days&amp;quot;,0) != 0)?&amp;quot;Klimatisierung&amp;lt;br&amp;gt;&amp;quot;.[Abfall_Abfuhr:Kiaheizen_connect_date].&amp;quot; &amp;quot;.[Abfall_Abfuhr:Kiaheizen_connect_time]:(([$SELF:ui_timer_mode] ne &amp;quot;Aus&amp;quot;)?&amp;quot;Klimatisierung&amp;lt;br&amp;gt;&amp;quot;.[$SELF:timer_04_c04]:&amp;quot;&amp;quot;))|FUNC_tire(&amp;quot;Kia_connect&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_door(&amp;quot;Kia_connect&amp;quot;)|\&lt;br /&gt;
&amp;quot;12 V&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([Kia_connect:bat12v])).STY(::round([Kia_connect:bat12v],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt; Auswahl / Temperatur / Klima Status / Temperatur innen&amp;lt;/dd&amp;gt;&amp;quot;| widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,stopClimate,startHeating,startCooling&amp;quot;)|\&lt;br /&gt;
&amp;quot;Heat&amp;quot;.widget([Kia_connect:status_airTemp_value_target_Winter],&amp;quot;selectnumbers,20,1,27,0,lin&amp;quot;).&amp;quot;°C&amp;lt;br&amp;gt;Cool&amp;quot;.widget([Kia_connect:status_airTemp_value_target_Sommer],&amp;quot;selectnumbers,16,1,25,0,lin&amp;quot;).&amp;quot;°C&amp;quot;|(([Kia_connect:status_airCtrlOn] eq &amp;quot;true&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Klima läuft&amp;lt;/span&amp;gt;&#039;:&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Klima aus&amp;lt;/span&amp;gt;&#039;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.(([Kia_connect:status_defrost] eq &amp;quot;true&amp;quot;)?&#039;Defrost ein&#039;:&#039;Defrost aus&#039;) |&amp;quot;Aktuell&amp;lt;br&amp;gt;&amp;quot;.[Kia_connect:status_airTemp_value].&amp;quot;°C&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;WallBox (WB_1_lp1)&amp;lt;dd&amp;gt;Lademodus / Info Status / Ladezeit / Leistung&amp;lt;/dd&amp;gt;&amp;quot;|[WB_1:ChargeMode].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_4],&amp;quot;uzsuDropDown,---,SofortLaden,Min+PV,NurPV,Stop,Standby,Vorrang_EV,Vorrang_Bat,Hausspeicher_Sperren&amp;quot;)|[WB_1:lp_1_PlugStat].&amp;quot; &amp;quot;.[WB_1:lp_1_ChargeStat]|[WB_1:lp_1_TimeRemaining]|[WB_1:lp_1_countPhasesInUse].&amp;quot;P &amp;quot;.[WB_1:lp_1_AConfigured].&amp;quot;A&amp;lt;br&amp;gt;&amp;quot;.[WB_1:lp_1_W].&amp;quot; W&amp;quot;&lt;br /&gt;
&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:24:24 ui_command_1 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-10 09:18:53 ui_command_2 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2021-11-09 07:56:54 ui_command_3 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:02:41 ui_command_4 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:02:41 ui_command_before_4 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2021-11-29 09:56:58 ui_timer_Start 10:30&lt;br /&gt;
setstate Kia_eNiro_PV 2021-12-02 07:00:00 ui_timer_mode Aus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore mit Speicher=====&lt;br /&gt;
Zu diesem Thema gibt es noch die Wiki Seite [[Kostal Plenticore Plus]], die alles rund um den Wechselrichter und vieles mehr erklärt.&lt;br /&gt;
Die hier beschriebene openWB und Kia connect Anbindung bedient sich der Hausspeichersteuerung, um diesen beim Laden der BEV zu sperren.&lt;br /&gt;
Im DOIF kann an den entsprechenden Stellen natürlich auch ein anders Kommando zum Sperren verwendet werden.&lt;br /&gt;
&lt;br /&gt;
== Weiterführende Links ==&lt;br /&gt;
* [https://openwb.de openWB Website]&lt;br /&gt;
* [https://github.com/snaptec/openWB/wiki openWB Wiki bei GitHub]&lt;br /&gt;
* [https://www.openwb.de/forum/viewtopic.php?f=6&amp;amp;t=4159 openWB Forum (Diskussion zu diesem Artikel)]&lt;br /&gt;
* [https://openwb.de/forum/viewtopic.php?t=577 openWB Forum (Liste der MQTT-Topics)]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Elektromobilität]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=OpenWB&amp;diff=39802</id>
		<title>OpenWB</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=OpenWB&amp;diff=39802"/>
		<updated>2025-01-12T15:55:54Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Node-red */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Integration der openWB in FHEM - Ladeleistung anzeigen und Umschalten des Lademodus ==&lt;br /&gt;
Ausgangssituation ist ein funktionierendes FHEM, ohne weitere Vorbedingungen.&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod openwb MQTT &amp;lt;openWBip&amp;gt;:1883&lt;br /&gt;
attr openwb room Auto,MQTT&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Dadurch wird der MQTT-Server der openWB angesprochen, FHEM ist der Client.&lt;br /&gt;
&lt;br /&gt;
Ein Ladepunkt wird als MQTT_Device angelegt:&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod lp1 MQTT_DEVICE&lt;br /&gt;
attr lp1 IODev openwb&lt;br /&gt;
attr lp1 publishSet_chargeMode openWB/set/ChargeMode&lt;br /&gt;
attr lp1 room Auto,Dashboard,MQTT&lt;br /&gt;
attr lp1 stateFormat power&lt;br /&gt;
attr lp1 subscribeReading_chargeMode openWB/global/ChargeMode&lt;br /&gt;
attr lp1 subscribeReading_plugStat openWB/lp/1/boolPlugStat&lt;br /&gt;
attr lp1 subscribeReading_power openWB/lp/1/W&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Die Umsetzung basiert auf openWB 1.9.x, der Lademodus &amp;quot;ChargeMode&amp;quot; gilt hier noch global für alle Ladepunkte.&lt;br /&gt;
&lt;br /&gt;
Beispielhaft die Definition des zweiten Ladepunktes, eine zweite openWB, die als &amp;quot;nur Ladepunkt&amp;quot; mit der angesprochenen openWB verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Eine openWB kann derzeit 8 Ladepunkte verwalten, die Nummern müssen entsprechend inkrementiert werden.&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod lp2 MQTT_DEVICE&lt;br /&gt;
attr lp2 IODev openwb&lt;br /&gt;
attr lp2 publishSet_chargeMode openWB/set/ChargeMode&lt;br /&gt;
attr lp2 room Auto,Dashboard,MQTT&lt;br /&gt;
attr lp2 stateFormat power&lt;br /&gt;
attr lp2 subscribeReading_chargeMode openWB/global/ChargeMode&lt;br /&gt;
attr lp2 subscribeReading_plugStat openWB/lp/2/boolPlugStat&lt;br /&gt;
attr lp2 subscribeReading_power openWB/lp/2/W&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Die MQTT-Topics zum Lesen und Schreiben von Werten sind ganz unten auf dieser Wiki-Seite zu finden.&lt;br /&gt;
&lt;br /&gt;
Die Einbindung in die TabletUI sieht bei mir so aus:&lt;br /&gt;
[[Datei:Ladepunkte in TabletUI.png|alternativtext=Darstellung der openWB Ladepunkte in der TabletUI|mini|488x488px|Beispielhafte Darstellung in der TabletUI]]&lt;br /&gt;
[[Datei:Auswahl des Lademodus.png|alternativtext=Darstellung der openWB Ladepunkte in der TabletUI - Auswahl des Lademodus|mini|486x486px|Auswahl des Lademodus per CircleMenu]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;cell-60 left-space right-space&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;div data-type=&amp;quot;symbol&amp;quot; data-icon=&amp;quot;fa-car&amp;quot; class=&amp;quot;tall compressed&amp;quot; data-color=&amp;quot;lightgray&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;div data-type=&amp;quot;circlemenu&amp;quot; data-direction=&amp;quot;full&amp;quot; class=&amp;quot;mini&amp;quot; style=&amp;quot;top: -0.5em;&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ul class=&amp;quot;mini&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-states=&#039;[0,1,2,3,4]&#039; data-colors=&#039;[&amp;quot;lightgreen&amp;quot;,&amp;quot;greenyellow&amp;quot;,&amp;quot;yellow&amp;quot;,&amp;quot;grey&amp;quot;,&amp;quot;black&amp;quot;]&#039; data-icons=&#039;[&amp;quot;fa-bolt&amp;quot;,&amp;quot;fa-plus-circle&amp;quot;,&amp;quot;fa-sun-o&amp;quot;,&amp;quot;fa-pause-circle-o&amp;quot;,&amp;quot;fa-stop-circle-o&amp;quot;]&#039; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;0&amp;quot; data-get-on=&amp;quot;0&amp;quot; data-icon=&amp;quot;fa-bolt&amp;quot; data-color=&amp;quot;lightgreen&amp;quot;  data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;1&amp;quot; data-get-on=&amp;quot;1&amp;quot; data-icon=&amp;quot;fa-plus-circle&amp;quot; data-color=&amp;quot;greenyellow&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;2&amp;quot; data-get-on=&amp;quot;2&amp;quot; data-icon=&amp;quot;fa-sun-o&amp;quot; data-color=&amp;quot;yellow&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;3&amp;quot; data-get-on=&amp;quot;3&amp;quot; data-icon=&amp;quot;fa-pause-circle-o&amp;quot; data-color=&amp;quot;grey&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;4&amp;quot; data-get-on=&amp;quot;4&amp;quot; data-icon=&amp;quot;fa-stop-circle-o&amp;quot; data-color=&amp;quot;black&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
			&amp;lt;/ul&amp;gt;&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;div style=&amp;quot;font-size: 30% !important;&amp;quot; class=&amp;quot;mini &amp;quot; data-pre-text=&amp;quot;&amp;quot; data-type=&amp;quot;label&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;power&amp;quot; data-unit=&amp;quot;&amp;quot; data-factor=&amp;quot;1&amp;quot; data-fix=&amp;quot;0&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;div data-type=&amp;quot;symbol&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;plugStat&amp;quot; data-states=&#039;[0,1]&#039; data-colors=&#039;[&amp;quot;white&amp;quot;,&amp;quot;black&amp;quot;]&#039; data-icons=&#039;[&amp;quot;&amp;quot;,&amp;quot;fa-plug&amp;quot;]&#039; data-background-icon=&amp;quot;&amp;quot; class=&amp;quot;mini&amp;quot; style=&amp;quot;font-size: 30% !important; top:1em;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Integration OpenWB in FHEM - Übertragung von EVU, PV und Batteriewerten an openWB==&lt;br /&gt;
Ausgangssituation ist ein funktionierendes FHEM-System, bei dem bereits der digitale Stromzähler (&amp;quot;Moderne Meßeinrichtung&amp;quot;) über das Modul 47_OBIS und der PV-Wechselrichter über ein entsprechendes Modul, z.B. ModbusAttr integriert sind. Als OpenWB-System wurde hier eine reale OpenWB-Wallbox angebunden.&lt;br /&gt;
&lt;br /&gt;
=== Datenquellen ===&lt;br /&gt;
Die OpenWB erwartet 1-3 Typen von Datenquellen in dieser Konstellation:&lt;br /&gt;
* Die &#039;&#039;EVU-&#039;&#039;Schnittstelle, mit der als wesentlicher Steuerparameter der Ladeleistung die Leistungsmessung am Hausübergang herangezogen wird, und daneben die Zählerwerte für Netzbezug und Einspeisung zur Visualisierung übertragen werden sollten. Nur, falls phasenbezogenes Lastmanagement erforderlich sein sollte, sind auch die einzelnen Phasenleistungswerte vom Stromzähler nötig (was nicht jede Moderne Meßeinrichtung auf der OBIS-Schnittstelle bereitstellt)&lt;br /&gt;
* Die &#039;&#039;PV-&#039;&#039;Schnittstelle, die ebenfalls primär visualisierende Bedeutung hat.&lt;br /&gt;
* Die &#039;&#039;Batteriespeicher-&#039;&#039;Schnittstelle&lt;br /&gt;
OpenWB kann auch z.B. rein mit einer PV-Schnittstelle betrieben werden, in diesem Fall wird ein konstanter Leistungswert für den Hausbezug angenommen.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikationsprotokoll ===&lt;br /&gt;
Zur Kommunikation mit FHEM bieten sich 2 Methoden an:&lt;br /&gt;
* &#039;&#039;&#039;HTTP&#039;&#039;&#039;-Abfrage durch OpenWB bei FHEM durch das generische HTTP-Modul von OpenWB  Diese Methode beschreibe ich nicht, weil sie mehr Overhead erzeugt und seitens FHEM die Einrichtung eines CSRF-Token-freien Web-Kanals erfordert&lt;br /&gt;
* &#039;&#039;&#039;MQTT&#039;&#039;&#039;-Push durch FHEM zur OpenWB  Diese Methode erscheint mir vorteilhafter, weil auf einer stehenden TCP-Verbindung lediglich Meßwerte gepusht werden.&lt;br /&gt;
&lt;br /&gt;
=== Implementierung ===&lt;br /&gt;
&lt;br /&gt;
==== Vorbereitung ====&lt;br /&gt;
In der OpenWB-Web-UI unter Modulkonfiguration die entsprechenden Module (EVU, PV, Batterie) auf MQTT stellen. Hinweis: Nicht alle dabei erscheinenden MQTT-Topics müssen mit Werten beliefert werden! Sowohl bei der EVU-Schnittstelle wie bei PV reichen Momentanleistung und Zählerstände für eine zufriedenstellende Anbindung!&lt;br /&gt;
&lt;br /&gt;
==== Definition der OpenWB als MQTT-Target ====&lt;br /&gt;
 defmod openwb_mqtt MQTT2_CLIENT &amp;lt;ip-der-openwb&amp;gt;:1883&lt;br /&gt;
 attr openwb_mqtt autocreate simple&lt;br /&gt;
 attr openwb_mqtt subscriptions openWB/lp/1/#&lt;br /&gt;
&lt;br /&gt;
==== Übertragung der EVU-Meßwerte ====&lt;br /&gt;
In diesem Beispiel heißt das die Stromzählerdaten liefernde Device am OBIS-Modul &amp;quot;MT175&amp;quot;. Die Zahlen werden per Notify von diesem Device auf MQTT kopiert:&lt;br /&gt;
 defmod openwb_evu_cons notify MT175:total_consumption:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/WhImported &amp;quot; . $EVTPART1); }&lt;br /&gt;
 defmod openwb_evu_feed notify MT175:total_feed:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/WhExported &amp;quot; . $EVTPART1); }&lt;br /&gt;
 defmod openwb_evu_w notify MT175:power:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/W &amp;quot; . int($EVTPART1)); }&lt;br /&gt;
&lt;br /&gt;
==== Übertragung der PV-Meßwerte ====&lt;br /&gt;
Sofern die Daten für Momentanleistung und Zählerstand direkt in einem Device vorliegen, können analoge Notifys für dieses Device implementiert werden. Die Zielwerte lauten:&lt;br /&gt;
* Für den Momentan-Leistungswert &amp;lt;code&amp;gt;openWB/set/pv/1/W&amp;lt;/code&amp;gt;&lt;br /&gt;
* Für den Zählerstand &amp;lt;code&amp;gt;openWB/set/pv/1/WhCounter&amp;lt;/code&amp;gt;&lt;br /&gt;
Dabei muss beachtet werden, dass - wie bei der EVU-Schnittstelle - nur Integerwerte für die Momentanleistung übertragen werden dürfen.&lt;br /&gt;
&lt;br /&gt;
==== Anbindung an Alexa ====&lt;br /&gt;
Der generische Smarthome-Skill &amp;quot;FHEMConnector&amp;quot; erlaubt nur die leider immer noch sehr limitierte Syntax von Amazon Alexa. Im Folgenden werden die Definitionen für die Befehle:&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen ein&amp;quot;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen aus&amp;quot;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen auf 6 (Prozent)&amp;quot;&#039;&#039;&lt;br /&gt;
dargestellt. &amp;quot;Überschussladen auf 6&amp;quot; bedeutet dabei real den &amp;quot;Min+PV&amp;quot;, also Überschussladen mit Minimalleistung von 6 Ampere. Je nach Tagesform von Amazon ist dabei das Sprechen von &amp;quot;Prozent&amp;quot; nötig, auch wenn dies natürlich sachlich falsch ist.&lt;br /&gt;
 define openwb_ueberschuss dummy&lt;br /&gt;
 attr openwb_ueberschuss alexaName Überschussladen&lt;br /&gt;
 attr openwb_ueberschuss genericDeviceType light&lt;br /&gt;
 attr openwb_ueberschuss readingList pct&lt;br /&gt;
 attr openwb_ueberschuss setList on off pct&lt;br /&gt;
 define openwb_ueberschuss_on notify openwb_ueberschuss:on set openwb_mqtt publish openWB/set/ChargeMode 2&lt;br /&gt;
 define openwb_ueberschuss_off notify openwb_ueberschuss:off set openwb_mqtt publish openWB/set/ChargeMode 3&lt;br /&gt;
 define openwb_ueberschuss_pct notify openwb_ueberschuss:pct:.* set openwb_mqtt publish openWB/config/set/pv/minCurrentMinPv $EVTPART1 ;; set openwb_mqtt publish openWB/set/ChargeMode 1&lt;br /&gt;
&lt;br /&gt;
==Anwendungs Beispiele==&lt;br /&gt;
===Komplexe Anbindung===&lt;br /&gt;
[[Bild:Kia.PNG|mini|700px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
Hier mal ein Beispiel mit weiteren Schnittstellen in der Haussteuerung. Im Hintergrund arbeitet ein Wechselrichter Schwarm mit einem Hausspeicher, der beim BEV Laden gesperrt wird. Die openWB kommuniziert direkt mit den zwei Kostal Wechselrichtern, dem KSEM und dem am Master angeschlossenen Speicher. Das BEV ist über Kia Connect angebunden.&lt;br /&gt;
[[Bild:WB_1.PNG|mini|700px|rechts|openWB mit Statistiken]]&lt;br /&gt;
[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss, inklusive Wechselrichter, raus kommen. Die openWBs sind unten links.]]&lt;br /&gt;
====Verwendete Schnittstellen / Devices====&lt;br /&gt;
=====openWB MQTT=====&lt;br /&gt;
Wie oben beschrieben mit folgender MQTT definition. Im Bild ist das DOIF dargestellt und das MQTT Device als kurze Darstellung unterhalb der Tabelle. Das MQTT wird nur zur Kopplung verwendet, hat jedoch jetzt auch ein stateFormat inklusieve Statistiken erhalten.&lt;br /&gt;
&lt;br /&gt;
RAW des MQTT Device&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WB_1 MQTT2_DEVICE WB_1_MQTT2&lt;br /&gt;
attr WB_1 DbLogExclude .*&lt;br /&gt;
attr WB_1 DbLogInclude lp_1_.*,.*AllChargePoints.*,ChargeMode&lt;br /&gt;
attr WB_1 IODev WB_1_MQTT2&lt;br /&gt;
attr WB_1 alias WB_1&lt;br /&gt;
attr WB_1 autocreate 0&lt;br /&gt;
attr WB_1 comment Die openWB besteht aus zwei Ladepunkten.&lt;br /&gt;
attr WB_1 devicetopic openWB&lt;br /&gt;
attr WB_1 disable 0&lt;br /&gt;
attr WB_1 event-on-change-reading lp_1_.*,.*AllChargePoints.*,ChargeMode&lt;br /&gt;
attr WB_1 group PV Eigenverbrauch&lt;br /&gt;
attr WB_1 icon fuel&lt;br /&gt;
attr WB_1 readingList $DEVICETOPIC/global/WHouseConsumption:.* WHouseConsumption\&lt;br /&gt;
$DEVICETOPIC/global/WAllChargePoints:.* WAllChargePoints\&lt;br /&gt;
$DEVICETOPIC/global/ChargeMode:.* {my %h=(0=&amp;gt;&#039;SofortLaden&#039;,1=&amp;gt;&#039;MinPV&#039;,2=&amp;gt;&#039;NurPV&#039;,3=&amp;gt;&#039;Stop&#039;,4=&amp;gt;&#039;Standby&#039;);; return {ChargeMode=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/global/awattar/boolAwattarEnabled:.* boolAwattarEnabled\&lt;br /&gt;
$DEVICETOPIC/global/awattar/ActualPriceForCharging:.* ActualPriceForCharging\&lt;br /&gt;
$DEVICETOPIC/global/awattar/MaxPriceForCharging:.* MaxPriceForCharging\&lt;br /&gt;
$DEVICETOPIC/global/boolRse:.* boolRse\&lt;br /&gt;
$DEVICETOPIC/global/DailyYieldAllChargePointsKwh:.* DailyYieldAllChargePointsKwh\&lt;br /&gt;
$DEVICETOPIC/global/rfidConfigured:.* rfidConfigured\&lt;br /&gt;
$DEVICETOPIC/global/kWhCounterAllChargePoints:.* kWhCounterAllChargePoints\&lt;br /&gt;
$DEVICETOPIC/global/strLastmanagementActive:.* strLastmanagementActive\&lt;br /&gt;
$DEVICETOPIC/global/ETProvider/modulePath:.* modulePath\&lt;br /&gt;
$DEVICETOPIC/global/cpuTemp:.* cpuTemp\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/system/Uptime:.* Uptime\&lt;br /&gt;
$DEVICETOPIC/system/Date:.* Date\&lt;br /&gt;
$DEVICETOPIC/system/Timestamp:.* Timestamp\&lt;br /&gt;
$DEVICETOPIC/system/Version:.* Version\&lt;br /&gt;
$DEVICETOPIC/system/IpAddress:.* IpAddress\&lt;br /&gt;
$DEVICETOPIC/system/lastRfId:.* lastRfId\&lt;br /&gt;
$DEVICETOPIC/system/updateInProgress:.* updateInProgress\&lt;br /&gt;
$DEVICETOPIC/system/ConfiguredChargePoints:.* ConfiguredChargePoints\&lt;br /&gt;
$DEVICETOPIC/system/lastlivevalues:.* lastlivevalues\&lt;br /&gt;
$DEVICETOPIC/system/randomSleep:.* randomSleep\&lt;br /&gt;
$DEVICETOPIC/system/wizzardDone:.* wizzardDone\&lt;br /&gt;
$DEVICETOPIC/system/priceForKWh:.* priceForKWh\&lt;br /&gt;
$DEVICETOPIC/system/reloadDisplay:.* reloadDisplay\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/evu/ASchieflast:.* ASchieflast\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/P%Soc:.* lp_1_Pct_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/1/%Soc:.* lp_1_current_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/1/\x25Soc:.* lp_1__Soc\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/countPhasesInUse:.* lp_1_countPhasesInUse\&lt;br /&gt;
$DEVICETOPIC/lp/1/ChargePointEnabled:.* lp_1_ChargePointEnabled\&lt;br /&gt;
$DEVICETOPIC/lp/1/ChargeStatus:.* lp_1_ChargeStatus\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhDailyCharged:.* lp_1_kWhDailyCharged\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhCounter:.* lp_1_kWhCounter\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhActualCharged:.* lp_1_kWhActualCharged\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhChargedSincePlugged:.* lp_1_kWhChargedSincePlugged\&lt;br /&gt;
$DEVICETOPIC/lp/1/energyConsumptionPer100km:.* lp_1_energyConsumptionPer100km\&lt;br /&gt;
$DEVICETOPIC/lp/1/kmCharged:.* lp_1_kmCharged\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/strChargePointName:.* lp_1_strChargePointName\&lt;br /&gt;
$DEVICETOPIC/lp/1/TimeRemaining:.* lp_1_TimeRemaining\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase2:.* lp_1_PfPhase2\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase3:.* lp_1_PfPhase3\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase1:.* lp_1_PfPhase1\&lt;br /&gt;
$DEVICETOPIC/lp/1/W:.* lp_1_W\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolPlugStat:.* {my %h=(0=&amp;gt;&#039;no Plug&#039;,1=&amp;gt;&#039;Plugged in&#039;);; return {lp_1_PlugStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargeStat:.* {my %h=(0=&amp;gt;&#039;not loading&#039;,1=&amp;gt;&#039;loading&#039;);; return {lp_1_ChargeStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/1/AConfigured:.* lp_1_AConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargePointConfigured:.* lp_1_boolChargePointConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolSocConfigured:.* lp_1_boolSocConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolDirectModeChargekWh:.* lp_1_boolDirectModeChargekWh\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolDirectChargeModeSoc:.* lp_1_boolDirectChargeModeSoc\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolFinishAtTimeChargeActive:.* lp_1_boolFinishAtTimeChargeActive\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargeAtNight:.* lp_1_boolChargeAtNight\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolSocManual:.* lp_1_boolSocManual\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/AutolockStatus:.* lp_1_AutolockStatus\&lt;br /&gt;
$DEVICETOPIC/lp/1/AutolockConfigured:.* lp_1_AutolockConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/lastRfId:.* lp_1_lastRfId\&lt;br /&gt;
$DEVICETOPIC/lp/1/pluggedladungakt:.* lp_1_pluggedladungakt\&lt;br /&gt;
$DEVICETOPIC/lp/1/plugStartkWh:.* lp_1_plugStartkWh\&lt;br /&gt;
$DEVICETOPIC/lp/1/MeterSerialNumber:.* lp_1_MeterSerialNumber\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/P%Soc:.* lp_2_Pct_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/2/%Soc:.* lp_2_current_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/2/\x25Soc:.* lp_2__Soc\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/countPhasesInUse:.* lp_2_countPhasesInUse\&lt;br /&gt;
$DEVICETOPIC/lp/2/ChargePointEnabled:.* lp_2_ChargePointEnabled\&lt;br /&gt;
$DEVICETOPIC/lp/2/ChargeStatus:.* lp_2_ChargeStatus\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhDailyCharged:.* lp_2_kWhDailyCharged\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhCounter:.* lp_2_kWhCounter\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhActualCharged:.* lp_2_kWhActualCharged\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhChargedSincePlugged:.* lp_2_kWhChargedSincePlugged\&lt;br /&gt;
$DEVICETOPIC/lp/2/energyConsumptionPer100km:.* lp_2_energyConsumptionPer100km\&lt;br /&gt;
$DEVICETOPIC/lp/2/kmCharged:.* lp_2_kmCharged\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/strChargePointName:.* lp_2_strChargePointName\&lt;br /&gt;
$DEVICETOPIC/lp/2/TimeRemaining:.* lp_2_TimeRemaining\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/W:.* lp_2_W\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolPlugStat:.* {my %h=(0=&amp;gt;&#039;no Plug&#039;,1=&amp;gt;&#039;Plugged in&#039;);; return {lp_2_PlugStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargeStat:.* {my %h=(0=&amp;gt;&#039;not loading&#039;,1=&amp;gt;&#039;loading&#039;);; return {lp_2_ChargeStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/2/AConfigured:.* lp_2_AConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargePointConfigured:.* lp_2_boolChargePointConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolSocConfigured:.* lp_2_boolSocConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolDirectModeChargekWh:.* lp_2_boolDirectModeChargekWh\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolDirectChargeModeSoc:.* lp_2_boolDirectChargeModeSoc\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolFinishAtTimeChargeActive:.* lp_2_boolFinishAtTimeChargeActive\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargeAtNight:.* lp_2_boolChargeAtNight\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolSocManual:.* lp_2_boolSocManual\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/AutolockStatus:.* lp_2_AutolockStatus\&lt;br /&gt;
$DEVICETOPIC/lp/2/AutolockConfigured:.* lp_2_AutolockConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/lastRfId:.* lp_2_lastRfId\&lt;br /&gt;
$DEVICETOPIC/lp/2/pluggedladungakt:.* lp_2_pluggedladungakt\&lt;br /&gt;
$DEVICETOPIC/lp/2/plugStartkWh:.* lp_2_plugStartkWh\&lt;br /&gt;
$DEVICETOPIC/lp/2/MeterSerialNumber:.* lp_2_MeterSerialNumber\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_direct:.* boolChargeAtNight_direct\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_nurpv:.* boolChargeAtNight_nurpv\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_minpv:.* boolChargeAtNight_minpv\&lt;br /&gt;
$DEVICETOPIC/boolDisplayHouseConsumption:.* boolDisplayHouseConsumption\&lt;br /&gt;
$DEVICETOPIC/boolDisplayDailyCharged:.* boolDisplayDailyCharged\&lt;br /&gt;
$DEVICETOPIC/boolEvuSmoothedActive:.* boolEvuSmoothedActive\&lt;br /&gt;
$DEVICETOPIC/pv/bool70PVDynActive:.* bool70PVDynActive\&lt;br /&gt;
$DEVICETOPIC/pv/W70PVDyn:.* W70PVDyn\&lt;br /&gt;
$DEVICETOPIC/pv/bool70PVDynStatus:.* bool70PVDynStatus\&lt;br /&gt;
$DEVICETOPIC/pv/CounterTillStartPvCharging:.* CounterTillStartPvCharging\&lt;br /&gt;
$DEVICETOPIC/pv/W:.* W\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/nurpv70dynact:.* nurpv70dynact\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/nurpv70dynw:.* nurpv70dynw\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/priorityModeEVBattery:.* priorityModeEVBattery\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minSocAlwaysToChargeTo:.* lp_1_minSocAlwaysToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/maxSoc:.* lp_1_maxSoc\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minSocAlwaysToChargeToCurrent:.* lp_1_minSocAlwaysToChargeToCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/maxSocToChargeTo:.* lp_1_maxSocToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minCurrent:.* lp_1_minCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/socLimitation:.* lp_1_socLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/minCurrent:.* lp_2_minCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/maxSoc:.* lp_2_maxSoc\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/socLimitation:.* lp_2_socLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/socStopChargeAtMinPv:.* socStopChargeAtMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/regulationPoint:.* regulationPoint\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minBatteryDischargeSocAtBattPriority:.* minBatteryDischargeSocAtBattPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minBatteryChargePowerAtEvPriority:.* minBatteryChargePowerAtEvPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minFeedinPowerBeforeStart:.* minFeedinPowerBeforeStart\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/boolAdaptiveCharging:.* boolAdaptiveCharging\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/adaptiveChargingFactor:.* adaptiveChargingFactor\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/batteryDischargePowerAtBattPriority:.* batteryDischargePowerAtBattPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/boolShowPriorityIconInTheme:.* boolShowPriorityIconInTheme\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/maxPowerConsumptionBeforeStop:.* maxPowerConsumptionBeforeStop\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/stopDelay:.* stopDelay\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/chargeSubmode:.* chargeSubmode\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minCurrentMinPv:.* minCurrentMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/socStartChargeAtMinPv:.* socStartChargeAtMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/startDelay:.* startDelay\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/energyToCharge:.* lp_2_energyToCharge\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/chargeLimitation:.* lp_2_chargeLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/socToChargeTo:.* lp_2_socToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/current:.* lp_2_current\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/socToChargeTo:.* lp_1_socToChargeTo\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/energyToCharge:.* lp_1_energyToCharge\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/chargeLimitation:.* lp_1_chargeLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/current:.* lp_1_current\&lt;br /&gt;
$DEVICETOPIC/config/get/global/minEVSECurrentAllowed:.* minEVSECurrentAllowed\&lt;br /&gt;
$DEVICETOPIC/config/get/global/maxEVSECurrentAllowed:.* maxEVSECurrentAllowed\&lt;br /&gt;
$DEVICETOPIC/config/get/global/dataProtectionAcknoledged:.* dataProtectionAcknoledged\&lt;br /&gt;
$DEVICETOPIC/config/get/global/slaveMode:.* slaveMode\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/standbyPhases:.* standbyPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/sofortPhases:.* sofortPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/nachtPhases:.* nachtPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/minundpvPhases:.* minundpvPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/nurpvPhases:.* nurpvPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/isConfigured:.* isConfigured\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_standby:.* boolChargeAtNight_standby\&lt;br /&gt;
$DEVICETOPIC/set/system/reloadDisplay:.* reloadDisplay\&lt;br /&gt;
$DEVICETOPIC/set/system/topicSender:.* topicSender\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/faultState:.* lp_2_faultState\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/faultStr:.* lp_2_faultStr\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/ChargePointEnabled:.* lp_2_ChargePointEnabled&lt;br /&gt;
attr WB_1 room MQTT2_DEVICE,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WB_1 setList Lademodus:SofortLaden,Min+PV,NurPV,Stop,Standby { my %h=(SofortLaden=&amp;gt;&#039;0&#039;,&#039;Min+PV&#039;=&amp;gt;&#039;1&#039;,NurPV=&amp;gt;&#039;2&#039;,Stop=&amp;gt;&#039;3&#039;,Standby=&amp;gt;&#039;4&#039;);;qq($DEVICETOPIC/set/ChargeMode $h{$EVTPART1}) }\&lt;br /&gt;
DirectChargeSubMode:Aus,kWh_Laden,SoC_Laden { my %h=(Aus=&amp;gt;&#039;0&#039;,kWh_Laden=&amp;gt;&#039;1&#039;,SoC_Laden=&amp;gt;&#039;2&#039;);;qq($DEVICETOPIC/set/lp1/DirectChargeSubMode $h{$EVTPART1}) }\&lt;br /&gt;
lp_1_socToChargeTo:50,60,70,80,90,100 { qq($DEVICETOPIC/config/set/sofort/lp/1/socToChargeTo $EVTPART1) }&lt;br /&gt;
attr WB_1 sortby 311&lt;br /&gt;
attr WB_1 stateFormat {\&lt;br /&gt;
 my $YearBefore=&#039;LogDBRep_Statistic_previous_Year&#039;;;\&lt;br /&gt;
 my $DUMMY  = &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $date = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;lastlivevalues&amp;quot;,0))));;\&lt;br /&gt;
\&lt;br /&gt;
 my $ChargeMode          = ReadingsVal($name,&amp;quot;ChargeMode&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
    $ChargeMode          = ($ChargeMode eq &amp;quot;SofortLaden&amp;quot;)? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;SofortLaden&amp;lt;/span&amp;gt;&amp;quot; : ($ChargeMode eq &amp;quot;MinPV&amp;quot;)?  &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Min+PV&amp;lt;/span&amp;gt;&amp;quot; : ($ChargeMode eq &amp;quot;NurPV&amp;quot;)?  &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;NurPV&amp;lt;/span&amp;gt;&amp;quot; : $ChargeMode;;\&lt;br /&gt;
 \&lt;br /&gt;
 my $lp_1_Name           = ReadingsVal($name,&amp;quot;lp_1_strChargePointName&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_1_Power          = ReadingsVal($name,&amp;quot;lp_1_W&amp;quot;,0).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_1        = ReadingsVal($name,&amp;quot;lp_1_countPhasesInUse&amp;quot;,0).&amp;quot;P &amp;quot;.ReadingsVal($name,&amp;quot;lp_1_AConfigured&amp;quot;,0).&amp;quot;A&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Status_1       = ReadingsVal($name,&amp;quot;lp_1_PlugStat&amp;quot;,&amp;quot;n/a&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_1_ChargeStat&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_1_Status_2       = ReadingsVal($name,&amp;quot;lp_1_TimeRemaining&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_1_Power_d        = ReadingsVal($name,&amp;quot;lp_1_kWhDailyCharged&amp;quot;,0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_m        = round(ReadingsVal($name,&amp;quot;lp_1_kWhCounter_Month&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_j        = sprintf(&amp;quot;%04d / %04d&amp;quot;,ReadingsVal($name,&amp;quot;lp_1_kWhCounter_Year&amp;quot;,0),ReadingsVal($YearBefore,&amp;quot;lp_1_kWhCounter_Year&amp;quot;,0));;\&lt;br /&gt;
 my $lp_1_Power_t        = round(ReadingsVal($name,&amp;quot;lp_1_kWhCounter&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_2_Name           = ReadingsVal($name,&amp;quot;lp_2_strChargePointName&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_2_Power          = ReadingsVal($name,&amp;quot;lp_2_W&amp;quot;,0).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_1        = ReadingsVal($name,&amp;quot;lp_2_countPhasesInUse&amp;quot;,0).&amp;quot;P &amp;quot;.ReadingsVal($name,&amp;quot;lp_2_AConfigured&amp;quot;,0).&amp;quot;A&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Status_1       = ReadingsVal($name,&amp;quot;lp_2_PlugStat&amp;quot;,&amp;quot;n/a&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_2_ChargeStat&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_2_Status_2       = &amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_2_TimeRemaining&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_2_Power_d        = ReadingsVal($name,&amp;quot;lp_2_kWhDailyCharged&amp;quot;,0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_m        = round(ReadingsVal($name,&amp;quot;lp_2_kWhCounter_Month&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_j        = sprintf(&amp;quot;%04d / %04d&amp;quot;,ReadingsVal($name,&amp;quot;lp_2_kWhCounter_Year&amp;quot;,0),ReadingsVal($YearBefore,&amp;quot;lp_2_kWhCounter_Year&amp;quot;,0));;\&lt;br /&gt;
 my $lp_2_Power_t        = round(ReadingsVal($name,&amp;quot;lp_2_kWhCounter&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Wallbox&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;$ChargeMode&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Status&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;Restladezeit&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;Leistung&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_1_Name.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Status_1.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Status_2.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_1.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$lp_1_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_2_Name.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Status_1.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Status_2.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_1.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$lp_2_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Statistik vom $date&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;aktuell&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Jahr/Vorjahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_1_Name.&amp;quot;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_d.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_m.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_j.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_2_Name.&amp;quot;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_d.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_m.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_j.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr WB_1 userReadings lp_1_kWhCounter_Month:lp_1_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter_init_Month&amp;quot;,0),0) },\&lt;br /&gt;
lp_1_kWhCounter_Year:lp_1_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter_init_Year&amp;quot;,0),0)  },\&lt;br /&gt;
\&lt;br /&gt;
lp_2_kWhCounter_Month:lp_2_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter_init_Month&amp;quot;,0),0) },\&lt;br /&gt;
lp_2_kWhCounter_Year:lp_2_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter_init_Year&amp;quot;,0),0)  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia connect MQTT=====&lt;br /&gt;
Das Kia_connect Device empfängt und sendet die MQTT Nachrichten zum Node-red Flow für das Kia BEV.&lt;br /&gt;
&lt;br /&gt;
RAW des Kia connect&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Kia_connect MQTT2_DEVICE&lt;br /&gt;
attr Kia_connect DbLogExclude .*&lt;br /&gt;
attr Kia_connect DbLogInclude .*&lt;br /&gt;
attr Kia_connect IODev MQTT2_FHEM_Server&lt;br /&gt;
attr Kia_connect alias Kia_connect&lt;br /&gt;
attr Kia_connect autocreate 1&lt;br /&gt;
attr Kia_connect devicetopic bluelinky&lt;br /&gt;
attr Kia_connect group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Kia_connect icon car&lt;br /&gt;
attr Kia_connect readingList $DEVICETOPIC/status:.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/location.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/odometer:.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/req_received:.* req_received\&lt;br /&gt;
$DEVICETOPIC/req_active:.* req_active&lt;br /&gt;
attr Kia_connect room MQTT2_DEVICE,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Kia_connect setList getOdometer req/$DEVICETOPIC/get_odometer get_odometer\&lt;br /&gt;
getStatus req/$DEVICETOPIC/get_status get_status\&lt;br /&gt;
getLocation req/$DEVICETOPIC/get_location get_location\&lt;br /&gt;
getTripinfo req/$DEVICETOPIC/get_tripinfo\&lt;br /&gt;
getAll req/$DEVICETOPIC/get_all get_all\&lt;br /&gt;
setChargeTargetSoc req/$DEVICETOPIC/set_chargetargets\&lt;br /&gt;
startCharge req/$DEVICETOPIC/start_charging start_charging\&lt;br /&gt;
stopCharge req/$DEVICETOPIC/stop_charging stop_charging\&lt;br /&gt;
stopClimate req/$DEVICETOPIC/stop_climate stop_climate\&lt;br /&gt;
startClimate req/$DEVICETOPIC/start_climate&lt;br /&gt;
attr Kia_connect sortby 402&lt;br /&gt;
attr Kia_connect stateFormat req_active&lt;br /&gt;
attr Kia_connect userReadings atHomeStanding:location.* { ((abs(AttrVal(&amp;quot;global&amp;quot;,&amp;quot;latitude&amp;quot;,49.85) - ReadingsVal($NAME,&amp;quot;location_coord_lat&amp;quot;,0)) &amp;lt;= 0.001) &amp;amp;&amp;amp; (abs(AttrVal(&amp;quot;global&amp;quot;,&amp;quot;longitude&amp;quot;,8.49) - ReadingsVal($NAME,&amp;quot;location_coord_lon&amp;quot;,0)) &amp;lt;= 0.001) &amp;amp;&amp;amp; (ReadingsVal($NAME,&amp;quot;location_speed_value&amp;quot;,1) == 0)) ? &#039;true&#039; : &#039;false&#039;;;;; },\&lt;br /&gt;
batSOC:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_batteryStatus&amp;quot;,0);;;;},\&lt;br /&gt;
connected:status.* { (ReadingsVal($NAME,&amp;quot;status_evStatus_batteryPlugin&amp;quot;,0) != 0) ? &#039;true&#039; : &#039;false&#039;;;;;},\&lt;br /&gt;
charging:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_batteryCharge&amp;quot;,&#039;false&#039;);;;;},\&lt;br /&gt;
targetSOC:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel&amp;quot;,0);;;;},\&lt;br /&gt;
time2targetSOC:status.* { my $t = ReadingsVal($NAME,&amp;quot;status_evStatus_remainTime2_atc_value&amp;quot;,1);;;; sprintf(&amp;quot;%02d:%02d&amp;quot;, $t/60%60, $t%60);;},\&lt;br /&gt;
range:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_drvDistance_1_rangeByFuel_totalAvailableRange_value&amp;quot;,0);;;;},\&lt;br /&gt;
bat12v:status.* { ReadingsVal($NAME,&amp;quot;status_battery_batSoc&amp;quot;,0);;;;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Node-red=====&lt;br /&gt;
[[Bild:Kia Flow.PNG|mini|900px|rechts|Node-red Kia Flow]]&lt;br /&gt;
Node-red habe ich einfach in einem Docker Container runter geladen und gestartet. Über Port 1880 kommt man direkt in die GUI und kann den ersten Flow laden.&lt;br /&gt;
&lt;br /&gt;
docker-compose .yml Eintrag&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
  node-red:&lt;br /&gt;
    image: nodered/node-red:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
    environment:&lt;br /&gt;
      - TZ=Europe/Berlin&lt;br /&gt;
    ports:&lt;br /&gt;
      - 1880:1880&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./node-red/data:/data&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Danach fehlt im Container noch folgende Erweiterung für den Node-red Flow&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
npm install node-red-contrib-bluelinky&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im MQTT muss dann noch der Benutzer und das Passwort abgelegt werden. Ansonst kommt nämlich im FHEM nichts a Dies muss direkt in node-red gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=====Kia Connect=====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Kia connect ist eine API für Kia und Hyundai E-Autos mit der man Daten vom Auto abfragen kann und auch einige Steuerungen möglich sind.&lt;br /&gt;
Mit Node-red und BlueLinky wird die Schnittstelle bedient.&lt;br /&gt;
Der Flow ist nicht ursprünglich von mir, wurde jedoch noch erweitert.&lt;br /&gt;
Vor dem Laden des Flows sind noch die persönlichen Verbindungsdaten im JSON einzutragen.&lt;br /&gt;
&lt;br /&gt;
Nach dem Laden ist ein Test mit den Inject Symbolen und der Debug Funktionalität möglich und auch sinnvoll.&lt;br /&gt;
Unterhalb der MQTT - und BlueLinky Symbole sollte &amp;quot;Verbunden&amp;quot; oder &amp;quot;Ready&amp;quot; erscheinen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wichtig beim Kia ist, dass für das Laden über die openWB als SOC Ziel 80% im standard Modus konfiguriert wird.&#039;&#039;&#039; Ansonsten wundert man sich warum das Laden einfach nicht starten möchte. Im Default ist dort bei mir nur 50% eingetragen gewesen :-). Mit jetzt 100% kann die openWB auch selber einen Ziel SOC bestimmen, ansonsten hört das BEV einfach selber auf zu laden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin sollte man darauf achten, dass man nur eine begrenzte Anzahl von Nachrichten mit dem Kia BEV pro Tag austauschen kann. Das wurde im DOIF schon etwas berücksichtigt (1x pro Stunde), kann jedoch bei gleichzeitiger Verwendung der Handy App oder der SOC Abfrage im openWB Kia Modul auch mal zu Fehlern führen. Durch die Stündliche Status Abfrage im DOIF kommt es natürlich zu Verzögerungen im FHEM Status. Dann einfach einmal Manuell abfragen.&lt;br /&gt;
&lt;br /&gt;
Node-red JSON Import&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
[    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;tab&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Kia e-Niro&amp;quot;,&lt;br /&gt;
        &amp;quot;disabled&amp;quot;: false,&lt;br /&gt;
        &amp;quot;info&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt-broker&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;mqtt_Server&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;&amp;lt;FHEM MQTT IP Adresse&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;port&amp;quot;: &amp;quot;1883&amp;quot;,&lt;br /&gt;
        &amp;quot;clientid&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;autoConnect&amp;quot;: true,&lt;br /&gt;
        &amp;quot;usetls&amp;quot;: false,&lt;br /&gt;
        &amp;quot;compatmode&amp;quot;: false,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;: &amp;quot;4&amp;quot;,&lt;br /&gt;
        &amp;quot;keepalive&amp;quot;: &amp;quot;60&amp;quot;,&lt;br /&gt;
        &amp;quot;cleansession&amp;quot;: true,&lt;br /&gt;
        &amp;quot;birthTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;birthQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;birthPayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;birthMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;closeTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;closeQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;closePayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;closeMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;willTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;willQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;willPayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;willMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;sessionExpiry&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;bluelinky&amp;quot;,&lt;br /&gt;
        &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Mail Adresse bei Kia&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Passwort&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;region&amp;quot;: &amp;quot;EU&amp;quot;,&lt;br /&gt;
        &amp;quot;pin&amp;quot;: &amp;quot;&amp;lt;Pin&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;vin&amp;quot;: &amp;quot;&amp;lt;VIN&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;brand&amp;quot;: &amp;quot;kia&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;91a345fa.5757a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_status&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;15dfb508.c6497b&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5ad085b9.05739c&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/start_climate&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;b27d74de.38c808&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;15dfb508.c6497b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-status&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get status&amp;quot;,&lt;br /&gt;
        &amp;quot;dorefresh&amp;quot;: true,&lt;br /&gt;
        &amp;quot;parsed&amp;quot;: false,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;cccc9476.d56dd8&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;87abdd88.8ff4d&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get car odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;40d2361c.579588&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;31100f9a.40008&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;locationWrapper&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;location\&amp;quot;: msg.payload,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;libs&amp;quot;: [],&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1490,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;bea1d927.0f3908&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-location&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get car location&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;31100f9a.40008&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3c949d67.0d83b2&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_location&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;bea1d927.0f3908&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;cccc9476.d56dd8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;analyseStatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    let status = msg.payload;\n    status.airTemp.value = 14+(parseInt(status.airTemp.value,16)/2);\n    try{\n    status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    } catch(e) {}\n\n    let time = status.evStatus.remainTime2.atc.value/60;\n    let result = { \n                 \&amp;quot;batSOC\&amp;quot;: status.evStatus.batteryStatus,\n                 \&amp;quot;connected\&amp;quot;: (status.evStatus.batteryPlugin !== 0),\n                 \&amp;quot;charging\&amp;quot;: status.evStatus.batteryCharge,\n                 \&amp;quot;targetSOC\&amp;quot;: status.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,\n                 \&amp;quot;time2targetSOC\&amp;quot;: (Math.floor(time) + \&amp;quot;:\&amp;quot; + (\&amp;quot;0\&amp;quot; + Math.floor((time % 1)*60)).slice(-2)), // h:mm\n                 \&amp;quot;range\&amp;quot;: status.evStatus.drvDistance[0].rangeByFuel.totalAvailableRange.value,\n                 \&amp;quot;bat12v\&amp;quot;: status.battery.batSoc\n                };\n    \n    //msg.payload = result;\n    msg.payload = {\n        \&amp;quot;status\&amp;quot;: status,\n        \&amp;quot;error\&amp;quot;: false\n        \n    };\n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1480,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/location&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/status&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1900,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;844a32f4.2e029&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/stop_climate&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7d3ae860.d8c9a8&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;57d91e50.7e96&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/start_charging&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 820,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;6eebc52c.ee23dc&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;6029f0a0.b73e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/stop_charging&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 880,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;84a1ae.74912e5&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;c5ecf76c.e753c8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;start-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Start car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;6eebc52c.ee23dc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;start-charge&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Start Charging&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 820,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;84a1ae.74912e5&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;stop-charge&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Stop Charging&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 880,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7d3ae860.d8c9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;stop-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Stop car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;b27d74de.38c808&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;obj&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;c5ecf76c.e753c8&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;45a6a8e6.2abfd8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;87abdd88.8ff4d&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 930,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 920,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/req_received&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 860,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 480,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;1babee6c.1c2982&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_all&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;,&lt;br /&gt;
                &amp;quot;4375fbb9.00fb44&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1850,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1470,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 930,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;24d5e0b.3aafc2&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;change&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;rules&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;t&amp;quot;: &amp;quot;set&amp;quot;,&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
                &amp;quot;pt&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
                &amp;quot;to&amp;quot;: &amp;quot;pending&amp;quot;,&lt;br /&gt;
                &amp;quot;tot&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;from&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;to&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;reg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 790,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1140,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
                &amp;quot;fecad185.324f8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;change&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;rules&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;t&amp;quot;: &amp;quot;set&amp;quot;,&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
                &amp;quot;pt&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
                &amp;quot;to&amp;quot;: &amp;quot;idle&amp;quot;,&lt;br /&gt;
                &amp;quot;tot&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;from&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;to&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;reg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
                &amp;quot;fecad185.324f8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/req_active&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 2140,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;fecad185.324f8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;false&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 2110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1160,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;40d2361c.579588&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;odometerWrapper&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    msg.payload = { \n        \&amp;quot;odometer\&amp;quot;: msg.payload,\n        \&amp;quot;error\&amp;quot;: false\n        };\n\n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;libs&amp;quot;: [],&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1490,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;226ed925.607bb6&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1430,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4375fbb9.00fb44&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-fullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get full status&amp;quot;,&lt;br /&gt;
        &amp;quot;dorefresh&amp;quot;: true,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;,&lt;br /&gt;
                &amp;quot;69b6c4df.ea6bcc&amp;quot;,&lt;br /&gt;
                &amp;quot;89681a97.9e24d8&amp;quot;,&lt;br /&gt;
                &amp;quot;92dc3ff4.1d6e3&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;69b6c4df.ea6bcc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;locationFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;location\&amp;quot;: msg.payload.vehicleLocation,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1500,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;92dc3ff4.1d6e3&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;statusFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    let status = msg.payload.vehicleStatus;\n    try{\n        status.airTemp.value = 14+(parseInt(status.airTemp.value,16)/2);\n        status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n        status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    } catch(e) {}\n\n    msg.payload = { \n        \&amp;quot;status\&amp;quot;: status,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1500,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 480,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;89681a97.9e24d8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;odometerFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;odometer\&amp;quot;: msg.payload.odometer,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1510,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 420,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;331e5860.907808&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1850,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 520,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;aa4d220b.f7e19&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;set-chargetargets&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Set charge targets&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4c03338d.2f15ec&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;login&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Login&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1090,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;28b868f5.16cb48&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;43200&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: true,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: &amp;quot;12&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 950,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4c03338d.2f15ec&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;db9ecdb5.a9683&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/set_chargetargets&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 290,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7064a8d53256b646&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;44155ad70c47b0dd&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;15dfb508.c6497b&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7064a8d53256b646&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;obj&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;aa4d220b.f7e19&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7064395e56292844&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 340,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4375fbb9.00fb44&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5f9ff828080f5fe6&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;lock-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Lock car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 560,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;492f5b94a865e47b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 540,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;5f9ff828080f5fe6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;d6f3f148e765caf9&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/car_lock&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 560,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;5f9ff828080f5fe6&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;cdc13a486db22b8e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/car_unlock&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 620,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;99f5c3a41ac3e754&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;99f5c3a41ac3e754&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unlock-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Unlock car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 620,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ab557a0ea621403a&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 600,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;99f5c3a41ac3e754&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;a525de86e4374518&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 740,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7d3ae860.d8c9a8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;0b8cb92c042fe140&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 800,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;6eebc52c.ee23dc&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ae4c2139b08aaa28&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 860,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;84a1ae.74912e5&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;dd23108ce63f456d&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;get-monthlyreport&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get monthly report&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;e57eb97531129426&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;a6e5e8deb52145f1&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1260,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;dd23108ce63f456d&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;95f1b6f32aafd65b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;get-tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;e57eb97531129426&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;fb2b99958bc48593&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;95f1b6f32aafd65b&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5230ebe391325b17&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: true,&lt;br /&gt;
        &amp;quot;rh&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;fb2b99958bc48593&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;e57eb97531129426&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1470,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4fdf3b1b7811c89f&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: true,&lt;br /&gt;
        &amp;quot;rh&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;dd23108ce63f456d&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia_eNiro_PV DOIF mit uiTable=====&lt;br /&gt;
Mit diesem DOIF Device werden folgende Funktionalitäten abgebildet:&lt;br /&gt;
Nun dann noch das DOIF mit dem uiTable für die Status Anzeige und die Steuerung über Pull Down Menüs.&lt;br /&gt;
&lt;br /&gt;
- Status Abfrage&lt;br /&gt;
     Status jede Stunde zwischen 6 und 23 Uhr (12V min 40%)&lt;br /&gt;
     Status beim Laden alle 15 Minuten (12V min 40%)&lt;br /&gt;
     Anzeige des Kilometerzählers&lt;br /&gt;
     Status des Fahrzeuges zu Hause / unterwegs und beim Laden&lt;br /&gt;
     Fahrzeug Auf/Zu&lt;br /&gt;
&lt;br /&gt;
- Klimatisierung über das Pull Down Menü&lt;br /&gt;
     unterschiedliche Temperaturen für Heizen und Kühlen&lt;br /&gt;
     Aktuelle Temperatur&lt;br /&gt;
     Heizen/Klima Ein/Aus&lt;br /&gt;
     Timer für zeitgesteuertes Klimatisieren für den Resttag oder den Nächsten Tag (vor der aktuellen Zeit)&lt;br /&gt;
     Klimatisierung über &amp;quot;Abfall&amp;quot; Kalender (es geht nur ein Termin pro Tag, dafür aber komfortabel über das Handy)&lt;br /&gt;
&lt;br /&gt;
- Komfort&lt;br /&gt;
     Reifen Überwachung&lt;br /&gt;
     Türen / Motorhaube / Kofferraum Überwachung&lt;br /&gt;
     12V Batterie anzeige, wenn der Ladezustand kleiner 40% ist erfolgt keine weitere Status Abfrage&lt;br /&gt;
&lt;br /&gt;
- ACCU Steuerung&lt;br /&gt;
    Setzen des Ziel SOC beim Standard Laden&lt;br /&gt;
    Start/Stop Laden&lt;br /&gt;
    Accu Stand und berechnete Restkilometer&lt;br /&gt;
&lt;br /&gt;
- Für openWB integratin im uiTable&lt;br /&gt;
    Wählen des Lademodus&lt;br /&gt;
    Vorrang EV oder Bat&lt;br /&gt;
    Sperren des Hausspeichers entweder manuell oder automatisch beim Laden. Der vorherige Zustand wird gespeichert&lt;br /&gt;
        Die Freigabe erfolgt über die Wechselrichter Implementierung, siehe dort [[Kostal_Plenticore_10_Plus#Externe_Speichersteuerung_.28ExternControl.29|&amp;quot;Externe Speicher Steuerung&amp;quot;]]&lt;br /&gt;
    Geschätzte Ladezeit&lt;br /&gt;
    Status Ladepunkt (Plug und Laden)&lt;br /&gt;
    Lade Status Phasen und Leistung   &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, die Kia connect Abfragen sind auf ca. 200 pro Tag von Kia limitiert! Durch die Stündliche Status Abfrage im DOIF kommt es natürlich zu Verzögerungen im FHEM Status. Dann einfach einmal manuell abfragen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Kommunikation zum Kia BEV ist manchmal sehr träge, z.B. kann eine Status Abfrage auch mal 3 Minuten dauern, deshalb wurde eine Verriegelung implementiert. Es wird ein Status pending/idle angezeigt. Nur wenn der Zustand &amp;quot;idel&amp;quot; ist, können weitere Abfragen gestartet werden. Läuft z.B. die Status Abfrage kann man ein weiteres Kommando anstarten, es wird jedoch erst abgesetzt, wenn das vorherige Kommando fertig ist. Solange bleibt im Pull Down Menü das neue Kommando stehen.&lt;br /&gt;
&lt;br /&gt;
RAW des DOIF&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Kia_eNiro_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Kia Connect Status Abfrage erfolgt mit MQTT2 ==&amp;gt; node-ret ==&amp;gt; Kia Connect\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_getAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (  ([+00:15] and                                                  ## alle 15 Minuten\&lt;br /&gt;
         [Kia_connect:atHomeStanding] eq &amp;quot;true&amp;quot; and                    ##   wenn das Auto zuhause ist\&lt;br /&gt;
         [Kia_connect:charging]       eq &amp;quot;true&amp;quot; or                     ##   und es geladen wird\&lt;br /&gt;
         [:58] and [05:00-23:00]                                       ## ansonsten nur jede Stunde\&lt;br /&gt;
        ) and [Kia_connect:bat12v] &amp;gt; 40                                ## aber die 12V Batterie sollte noch genügend Ladung haben\&lt;br /&gt;
      or [$SELF:cmd_event]  eq &amp;quot;set_cmd_1&amp;quot;                             ## Das reagiert auf den Aufruf mit &amp;quot;set &amp;lt;Device&amp;gt; cmd_*&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_getAll&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_getAll&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_before_1&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    fhem_set(&amp;quot;Kia_connect getAll&amp;quot;);;                                    ## beliebige Kommandos für diesen Block\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_Klima\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_2] eq &amp;quot;stopClimate&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;startHeating&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;startCooling&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_2&amp;quot;,[$SELF:ui_command_2]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;startHeating&amp;quot;) {\&lt;br /&gt;
      my $airTemp_value= [Kia_connect:status_airTemp_value_target_Winter];;\&lt;br /&gt;
      fhem_set(&#039;Kia_connect startClimate {&amp;quot;defrost&amp;quot;: true, &amp;quot;windscreenHeating&amp;quot;: true, &amp;quot;temperature&amp;quot;: &#039;.$airTemp_value.&#039; , &amp;quot;unit&amp;quot;: &amp;quot;C&amp;quot;}&#039;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : startHeating&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;startCooling&amp;quot;) {\&lt;br /&gt;
      my $airTemp_value = [Kia_connect:status_airTemp_value_target_Summer];;\&lt;br /&gt;
      fhem_set(&#039;Kia_connect startClimate {&amp;quot;defrost&amp;quot;: false, &amp;quot;windscreenHeating&amp;quot;: false, &amp;quot;temperature&amp;quot;: &#039;.$airTemp_value.&#039; , &amp;quot;unit&amp;quot;: &amp;quot;C&amp;quot;}&#039;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : startCooling&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;stopClimate&amp;quot;) {\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_2]);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : stopClimate&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    fhem_set(&amp;quot;Abfall update&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_Laden\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_3] eq &amp;quot;setChargeTargetSoc&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_3] eq &amp;quot;startCharge&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_3] eq &amp;quot;stopCharge&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_3&amp;quot;,[$SELF:ui_command_3]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_3] eq &amp;quot;setChargeTargetSoc&amp;quot;) {\&lt;br /&gt;
      my $targetSOClist_1_targetSOClevel = [Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_1_targetSOClevel_target];;\&lt;br /&gt;
      my $targetSOClist_2_targetSOClevel = [Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel_target];;\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect setChargeTargetSoc {\&amp;quot;fast\&amp;quot;: &amp;quot;.$targetSOClist_1_targetSOClevel.&amp;quot;, \&amp;quot;slow\&amp;quot;: &amp;quot;.$targetSOClist_2_targetSOClevel.&amp;quot;}&amp;quot;);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_3]);;                   ## beliebige Kommandos für diesen Block\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_3&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
4_Klima_timer_heizen\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       (    [[Abfall_Abfuhr:Kiaheizen_connect_time]]                   ## Prüfe den Kalender Eintrag\&lt;br /&gt;
        and [Abfall_Abfuhr:Kiaheizen_connect_date] eq $ymd             ##   ist es heute?\&lt;br /&gt;
       )\&lt;br /&gt;
       or\&lt;br /&gt;
       (    [$SELF:ui_timer_mode] eq &amp;quot;heizen&amp;quot;                          ## Timer zum Heizen aktiv?\&lt;br /&gt;
        and [[$SELF:ui_timer_Start]]                                   ##   ist es soweit?\&lt;br /&gt;
       )\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 4_Klima_timer : startHeating&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_timer_mode&amp;quot;,&amp;quot;Aus&amp;quot;);;                                ## Schalte die Timer Funktion ab\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;startHeating&amp;quot;);;                        ## Es soll geheizt werden\&lt;br /&gt;
    fhem_set(&amp;quot;$SELF 2_Klima&amp;quot;);;                                         ## Aktiviere das Heizen\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
5_Klima_timer_kuehlen\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       (    [[Abfall_Abfuhr:Kiakuehlen_connect_time]]                  ## Prüfe den Kalender Eintrag\&lt;br /&gt;
        and [Abfall_Abfuhr:Kiakuehlen_connect_date] eq $ymd            ##   ist es heute?\&lt;br /&gt;
       )\&lt;br /&gt;
       or\&lt;br /&gt;
       (    [$SELF:ui_timer_mode] eq &amp;quot;kuehlen&amp;quot;                         ## Timer zum Kühler aktiv?\&lt;br /&gt;
        and [[$SELF:ui_timer_Start]]                                   ##   ist es soweit?\&lt;br /&gt;
       )\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 4_Klima_timer : startCooling&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_timer_mode&amp;quot;,&amp;quot;Aus&amp;quot;);;                                ## Schalte die Timer Funktion ab\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;startCooling&amp;quot;);;                        ## Es soll gekühlt werden\&lt;br /&gt;
    fhem_set(&amp;quot;$SELF 2_Klima&amp;quot;);;                                         ## Aktiviere das Kühlen\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
6_Auf_Zu\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_2] eq &amp;quot;car_lock&amp;quot;                            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;car_unlock&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_2&amp;quot;,[$SELF:ui_command_2]);;\&lt;br /&gt;
\&lt;br /&gt;
    fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_2]);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 6_Auf_Zu      : &amp;quot;.[$SELF:ui_command_2]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
7_WB_1_lp_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_4] eq &amp;quot;SofortLaden&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Min+PV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;NurPV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Stop&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Standby&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Vorrang_Bat&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_4&amp;quot;,[$SELF:ui_command_4]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_4] eq &amp;quot;Vorrang_Bat&amp;quot; or [$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;) {\&lt;br /&gt;
      if ([$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;) {\&lt;br /&gt;
        fhem_set(&amp;quot;WB_1 priorityModeEVBattery 1&amp;quot;);;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem_set(&amp;quot;WB_1 priorityModeEVBattery 0&amp;quot;);;\&lt;br /&gt;
      }\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 7_WB_1_lp_1    : &amp;quot;.[$SELF:ui_command_4]};;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      fhem_set(&amp;quot;WB_1 Lademodus &amp;quot;.[$SELF:ui_command_4]);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 7_WB_1_lp_1    : Lademodus &amp;quot;.[$SELF:ui_command_4]};;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_4&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
8_Speicher_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_4]   eq &amp;quot;Hausspeicher_Sperren&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot; and\&lt;br /&gt;
         [WB_1:lp_1_PlugStat]   eq &amp;quot;Plugged in&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_4&amp;quot;,[$SELF:ui_command_4]);;\&lt;br /&gt;
\&lt;br /&gt;
    if([$SELF:WR_1_Speicher_1_ExternControl_smart_laden_before] eq &amp;quot;---&amp;quot;) {\&lt;br /&gt;
\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        set_Reading(&amp;quot;WR_1_Speicher_1_ExternControl_smart_laden_before&amp;quot;,&amp;quot;aktiv&amp;quot;);;\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        set_Reading(&amp;quot;WR_1_Speicher_1_ExternControl_smart_laden_before&amp;quot;,&amp;quot;inaktiv&amp;quot;);;\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      fhem_set(&amp;quot;WR_1_Speicher_1_ExternControl cmd_2&amp;quot;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_Laden startet&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_4&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
9_WB_1_Zaehler_Statistiken\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;) and                                     ## DOIF enabled\&lt;br /&gt;
     [00:01]\&lt;br /&gt;
   ) {\&lt;br /&gt;
    fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Day &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
    fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Day &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Month &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Month &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Year &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Year &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Kia_eNiro_PV DbLogExclude .*&lt;br /&gt;
attr Kia_eNiro_PV disable 0&lt;br /&gt;
attr Kia_eNiro_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Kia_eNiro_PV icon car&lt;br /&gt;
attr Kia_eNiro_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Kia_eNiro_PV sortby 401&lt;br /&gt;
attr Kia_eNiro_PV uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status_Laden {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $charge = (::ReadingsVal($car,&amp;quot;charging&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
   my $athome = (::ReadingsVal($car,&amp;quot;atHomeStanding&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
   my $chargeathome = ($charge &amp;amp;&amp;amp; $athome);;\&lt;br /&gt;
   my $connectedathome = ($athome &amp;amp;&amp;amp; ::ReadingsVal($car,&amp;quot;connected&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   my $ret = ($chargeathome ? &amp;quot;lädt zu Hause&amp;quot; : ($connectedathome ? &amp;quot;angeschlossen zu Hause&amp;quot; : ($athome ? &amp;quot;zu Hause&amp;quot; : ($charge ? &amp;quot;Lädt auswärts&amp;quot; : &amp;quot;unterwegs&amp;quot;))));;\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_tire {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $ret = &#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Reifendruck okay&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampAll&amp;quot;,&amp;quot;1&amp;quot;) != 0) {\&lt;br /&gt;
     my $VL = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampFL&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $HL = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampRL&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $VR = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampFR&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $HR = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampRR&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     $ret = &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Reifen Störung&amp;lt;br&amp;gt;&#039;;;\&lt;br /&gt;
     if ($VL == 1){$ret.=&#039; /VL&#039;};;\&lt;br /&gt;
     if ($VR == 1){$ret.=&#039; /VR&#039;};;\&lt;br /&gt;
     if ($HL == 1){$ret.=&#039; /HL&#039;};;\&lt;br /&gt;
     if ($HR == 1){$ret.=&#039; /HR&#039;};;\&lt;br /&gt;
     $ret = $ret.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_door {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $ret = &#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Türen okay&amp;lt;br&amp;gt;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_doorLock&amp;quot;,&amp;quot;false&amp;quot;) ne &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     my $VL = (::ReadingsVal($car,&amp;quot;status_doorOpen_frontLeft&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $HL = (::ReadingsVal($car,&amp;quot;status_doorOpen_backLeft&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $VR = (::ReadingsVal($car,&amp;quot;status_doorOpen_frontRight&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $HR = (::ReadingsVal($car,&amp;quot;status_doorOpen_backRight&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     $ret = &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Tür offen&amp;lt;br&amp;gt;&#039;;;\&lt;br /&gt;
     if ($VL == 1){$ret.=&#039; /VL&#039;};;\&lt;br /&gt;
     if ($VR == 1){$ret.=&#039; /VR&#039;};;\&lt;br /&gt;
     if ($HL == 1){$ret.=&#039; /HL&#039;};;\&lt;br /&gt;
     if ($HR == 1){$ret.=&#039; /HR&#039;};;\&lt;br /&gt;
     $ret = $ret.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_trunkOpen&amp;quot;,&amp;quot;true&amp;quot;) eq &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     $ret.=&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt; Kofferraum offen&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_hoodOpen&amp;quot;,&amp;quot;true&amp;quot;) eq &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     $ret.=&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt; Motorhaube offen&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando &amp;quot;.::ReadingsTimestamp(&amp;quot;Kia_connect&amp;quot;,&amp;quot;status_time&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Auswahl / Kommunikation / Tacho / Info Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_getAll,car_lock,car_unlock&amp;quot;)|(([Kia_connect:req_active] eq &amp;quot;idle&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;idle&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;.[Kia_connect:req_active].&#039;&amp;lt;/span&amp;gt;&#039;) |::round([Kia_connect:odometer_value],0).&amp;quot; km&amp;quot;|FUNC_Status_Laden(&amp;quot;Kia_connect&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Accu&amp;lt;dd&amp;gt;Steuerung / Target Soc / Accu Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_3],&amp;quot;uzsuDropDown,---,setChargeTargetSoc,stopCharge,startCharge&amp;quot;)|&amp;quot;Target SOC&amp;quot;.widget([Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel_target],&amp;quot;selectnumbers,50,10,100,0,lin&amp;quot;).&amp;quot; %&amp;quot;|&amp;quot;&amp;quot;| FUNC_Status([Kia_connect:range],150,&amp;quot;red&amp;quot;,[Kia_connect:range],&amp;quot;orange&amp;quot;,[Kia_connect:range],250,&amp;quot;green&amp;quot;,[Kia_connect:range]).&amp;quot; km&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([Kia_connect:batSOC])).STY(::round([Kia_connect:batSOC],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Komfort&amp;lt;dd&amp;gt;Timer / Klima / Reifen / Türen / Accu Status 12V&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_timer_mode],&amp;quot;uzsuDropDown,Aus,heizen,kuehlen&amp;quot;).widget([$SELF:ui_timer_Start],&amp;quot;time&amp;quot;)|\&lt;br /&gt;
((::ReadingsVal(&amp;quot;Abfall_Abfuhr&amp;quot;,&amp;quot;Kiaheizen_days&amp;quot;,0) != 0)?&amp;quot;Klimatisierung&amp;lt;br&amp;gt;&amp;quot;.[Abfall_Abfuhr:Kiaheizen_connect_date].&amp;quot; &amp;quot;.[Abfall_Abfuhr:Kiaheizen_connect_time]:(([$SELF:ui_timer_mode] ne &amp;quot;Aus&amp;quot;)?&amp;quot;Klimatisierung&amp;lt;br&amp;gt;&amp;quot;.[$SELF:timer_04_c04]:&amp;quot;&amp;quot;))|FUNC_tire(&amp;quot;Kia_connect&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_door(&amp;quot;Kia_connect&amp;quot;)|\&lt;br /&gt;
&amp;quot;12 V&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([Kia_connect:bat12v])).STY(::round([Kia_connect:bat12v],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt; Auswahl / Temperatur / Klima Status / Temperatur innen&amp;lt;/dd&amp;gt;&amp;quot;| widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,stopClimate,startHeating,startCooling&amp;quot;)|\&lt;br /&gt;
&amp;quot;Heat&amp;quot;.widget([Kia_connect:status_airTemp_value_target_Winter],&amp;quot;selectnumbers,20,1,27,0,lin&amp;quot;).&amp;quot;°C&amp;lt;br&amp;gt;Cool&amp;quot;.widget([Kia_connect:status_airTemp_value_target_Sommer],&amp;quot;selectnumbers,16,1,25,0,lin&amp;quot;).&amp;quot;°C&amp;quot;|(([Kia_connect:status_airCtrlOn] eq &amp;quot;true&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Klima läuft&amp;lt;/span&amp;gt;&#039;:&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Klima aus&amp;lt;/span&amp;gt;&#039;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.(([Kia_connect:status_defrost] eq &amp;quot;true&amp;quot;)?&#039;Defrost ein&#039;:&#039;Defrost aus&#039;) |&amp;quot;Aktuell&amp;lt;br&amp;gt;&amp;quot;.[Kia_connect:status_airTemp_value].&amp;quot;°C&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;WallBox (WB_1_lp1)&amp;lt;dd&amp;gt;Lademodus / Info Status / Ladezeit / Leistung&amp;lt;/dd&amp;gt;&amp;quot;|[WB_1:ChargeMode].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_4],&amp;quot;uzsuDropDown,---,SofortLaden,Min+PV,NurPV,Stop,Standby,Vorrang_EV,Vorrang_Bat,Hausspeicher_Sperren&amp;quot;)|[WB_1:lp_1_PlugStat].&amp;quot; &amp;quot;.[WB_1:lp_1_ChargeStat]|[WB_1:lp_1_TimeRemaining]|[WB_1:lp_1_countPhasesInUse].&amp;quot;P &amp;quot;.[WB_1:lp_1_AConfigured].&amp;quot;A&amp;lt;br&amp;gt;&amp;quot;.[WB_1:lp_1_W].&amp;quot; W&amp;quot;&lt;br /&gt;
&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:24:24 ui_command_1 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-10 09:18:53 ui_command_2 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2021-11-09 07:56:54 ui_command_3 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:02:41 ui_command_4 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:02:41 ui_command_before_4 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2021-11-29 09:56:58 ui_timer_Start 10:30&lt;br /&gt;
setstate Kia_eNiro_PV 2021-12-02 07:00:00 ui_timer_mode Aus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore mit Speicher=====&lt;br /&gt;
Zu diesem Thema gibt es noch die Wiki Seite [[Kostal Plenticore Plus]], die alles rund um den Wechselrichter und vieles mehr erklärt.&lt;br /&gt;
Die hier beschriebene openWB und Kia connect Anbindung bedient sich der Hausspeichersteuerung, um diesen beim Laden der BEV zu sperren.&lt;br /&gt;
Im DOIF kann an den entsprechenden Stellen natürlich auch ein anders Kommando zum Sperren verwendet werden.&lt;br /&gt;
&lt;br /&gt;
== Weiterführende Links ==&lt;br /&gt;
* [https://openwb.de openWB Website]&lt;br /&gt;
* [https://github.com/snaptec/openWB/wiki openWB Wiki bei GitHub]&lt;br /&gt;
* [https://www.openwb.de/forum/viewtopic.php?f=6&amp;amp;t=4159 openWB Forum (Diskussion zu diesem Artikel)]&lt;br /&gt;
* [https://openwb.de/forum/viewtopic.php?t=577 openWB Forum (Liste der MQTT-Topics)]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Elektromobilität]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=OpenWB&amp;diff=39801</id>
		<title>OpenWB</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=OpenWB&amp;diff=39801"/>
		<updated>2025-01-12T15:53:15Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Kia_eNiro_PV DOIF mit uiTable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Integration der openWB in FHEM - Ladeleistung anzeigen und Umschalten des Lademodus ==&lt;br /&gt;
Ausgangssituation ist ein funktionierendes FHEM, ohne weitere Vorbedingungen.&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod openwb MQTT &amp;lt;openWBip&amp;gt;:1883&lt;br /&gt;
attr openwb room Auto,MQTT&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Dadurch wird der MQTT-Server der openWB angesprochen, FHEM ist der Client.&lt;br /&gt;
&lt;br /&gt;
Ein Ladepunkt wird als MQTT_Device angelegt:&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod lp1 MQTT_DEVICE&lt;br /&gt;
attr lp1 IODev openwb&lt;br /&gt;
attr lp1 publishSet_chargeMode openWB/set/ChargeMode&lt;br /&gt;
attr lp1 room Auto,Dashboard,MQTT&lt;br /&gt;
attr lp1 stateFormat power&lt;br /&gt;
attr lp1 subscribeReading_chargeMode openWB/global/ChargeMode&lt;br /&gt;
attr lp1 subscribeReading_plugStat openWB/lp/1/boolPlugStat&lt;br /&gt;
attr lp1 subscribeReading_power openWB/lp/1/W&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Die Umsetzung basiert auf openWB 1.9.x, der Lademodus &amp;quot;ChargeMode&amp;quot; gilt hier noch global für alle Ladepunkte.&lt;br /&gt;
&lt;br /&gt;
Beispielhaft die Definition des zweiten Ladepunktes, eine zweite openWB, die als &amp;quot;nur Ladepunkt&amp;quot; mit der angesprochenen openWB verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Eine openWB kann derzeit 8 Ladepunkte verwalten, die Nummern müssen entsprechend inkrementiert werden.&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod lp2 MQTT_DEVICE&lt;br /&gt;
attr lp2 IODev openwb&lt;br /&gt;
attr lp2 publishSet_chargeMode openWB/set/ChargeMode&lt;br /&gt;
attr lp2 room Auto,Dashboard,MQTT&lt;br /&gt;
attr lp2 stateFormat power&lt;br /&gt;
attr lp2 subscribeReading_chargeMode openWB/global/ChargeMode&lt;br /&gt;
attr lp2 subscribeReading_plugStat openWB/lp/2/boolPlugStat&lt;br /&gt;
attr lp2 subscribeReading_power openWB/lp/2/W&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Die MQTT-Topics zum Lesen und Schreiben von Werten sind ganz unten auf dieser Wiki-Seite zu finden.&lt;br /&gt;
&lt;br /&gt;
Die Einbindung in die TabletUI sieht bei mir so aus:&lt;br /&gt;
[[Datei:Ladepunkte in TabletUI.png|alternativtext=Darstellung der openWB Ladepunkte in der TabletUI|mini|488x488px|Beispielhafte Darstellung in der TabletUI]]&lt;br /&gt;
[[Datei:Auswahl des Lademodus.png|alternativtext=Darstellung der openWB Ladepunkte in der TabletUI - Auswahl des Lademodus|mini|486x486px|Auswahl des Lademodus per CircleMenu]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;cell-60 left-space right-space&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;div data-type=&amp;quot;symbol&amp;quot; data-icon=&amp;quot;fa-car&amp;quot; class=&amp;quot;tall compressed&amp;quot; data-color=&amp;quot;lightgray&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;div data-type=&amp;quot;circlemenu&amp;quot; data-direction=&amp;quot;full&amp;quot; class=&amp;quot;mini&amp;quot; style=&amp;quot;top: -0.5em;&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ul class=&amp;quot;mini&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-states=&#039;[0,1,2,3,4]&#039; data-colors=&#039;[&amp;quot;lightgreen&amp;quot;,&amp;quot;greenyellow&amp;quot;,&amp;quot;yellow&amp;quot;,&amp;quot;grey&amp;quot;,&amp;quot;black&amp;quot;]&#039; data-icons=&#039;[&amp;quot;fa-bolt&amp;quot;,&amp;quot;fa-plus-circle&amp;quot;,&amp;quot;fa-sun-o&amp;quot;,&amp;quot;fa-pause-circle-o&amp;quot;,&amp;quot;fa-stop-circle-o&amp;quot;]&#039; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;0&amp;quot; data-get-on=&amp;quot;0&amp;quot; data-icon=&amp;quot;fa-bolt&amp;quot; data-color=&amp;quot;lightgreen&amp;quot;  data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;1&amp;quot; data-get-on=&amp;quot;1&amp;quot; data-icon=&amp;quot;fa-plus-circle&amp;quot; data-color=&amp;quot;greenyellow&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;2&amp;quot; data-get-on=&amp;quot;2&amp;quot; data-icon=&amp;quot;fa-sun-o&amp;quot; data-color=&amp;quot;yellow&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;3&amp;quot; data-get-on=&amp;quot;3&amp;quot; data-icon=&amp;quot;fa-pause-circle-o&amp;quot; data-color=&amp;quot;grey&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li&amp;gt;&amp;lt;div data-type=&amp;quot;push&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-set=&amp;quot;chargeMode&amp;quot; data-get=&amp;quot;chargeMode&amp;quot; data-set-on=&amp;quot;4&amp;quot; data-get-on=&amp;quot;4&amp;quot; data-icon=&amp;quot;fa-stop-circle-o&amp;quot; data-color=&amp;quot;black&amp;quot; data-background-icon=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
			&amp;lt;/ul&amp;gt;&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;div style=&amp;quot;font-size: 30% !important;&amp;quot; class=&amp;quot;mini &amp;quot; data-pre-text=&amp;quot;&amp;quot; data-type=&amp;quot;label&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;power&amp;quot; data-unit=&amp;quot;&amp;quot; data-factor=&amp;quot;1&amp;quot; data-fix=&amp;quot;0&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
		&amp;lt;div data-type=&amp;quot;symbol&amp;quot; data-device=&amp;quot;lp1&amp;quot; data-get=&amp;quot;plugStat&amp;quot; data-states=&#039;[0,1]&#039; data-colors=&#039;[&amp;quot;white&amp;quot;,&amp;quot;black&amp;quot;]&#039; data-icons=&#039;[&amp;quot;&amp;quot;,&amp;quot;fa-plug&amp;quot;]&#039; data-background-icon=&amp;quot;&amp;quot; class=&amp;quot;mini&amp;quot; style=&amp;quot;font-size: 30% !important; top:1em;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Integration OpenWB in FHEM - Übertragung von EVU, PV und Batteriewerten an openWB==&lt;br /&gt;
Ausgangssituation ist ein funktionierendes FHEM-System, bei dem bereits der digitale Stromzähler (&amp;quot;Moderne Meßeinrichtung&amp;quot;) über das Modul 47_OBIS und der PV-Wechselrichter über ein entsprechendes Modul, z.B. ModbusAttr integriert sind. Als OpenWB-System wurde hier eine reale OpenWB-Wallbox angebunden.&lt;br /&gt;
&lt;br /&gt;
=== Datenquellen ===&lt;br /&gt;
Die OpenWB erwartet 1-3 Typen von Datenquellen in dieser Konstellation:&lt;br /&gt;
* Die &#039;&#039;EVU-&#039;&#039;Schnittstelle, mit der als wesentlicher Steuerparameter der Ladeleistung die Leistungsmessung am Hausübergang herangezogen wird, und daneben die Zählerwerte für Netzbezug und Einspeisung zur Visualisierung übertragen werden sollten. Nur, falls phasenbezogenes Lastmanagement erforderlich sein sollte, sind auch die einzelnen Phasenleistungswerte vom Stromzähler nötig (was nicht jede Moderne Meßeinrichtung auf der OBIS-Schnittstelle bereitstellt)&lt;br /&gt;
* Die &#039;&#039;PV-&#039;&#039;Schnittstelle, die ebenfalls primär visualisierende Bedeutung hat.&lt;br /&gt;
* Die &#039;&#039;Batteriespeicher-&#039;&#039;Schnittstelle&lt;br /&gt;
OpenWB kann auch z.B. rein mit einer PV-Schnittstelle betrieben werden, in diesem Fall wird ein konstanter Leistungswert für den Hausbezug angenommen.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikationsprotokoll ===&lt;br /&gt;
Zur Kommunikation mit FHEM bieten sich 2 Methoden an:&lt;br /&gt;
* &#039;&#039;&#039;HTTP&#039;&#039;&#039;-Abfrage durch OpenWB bei FHEM durch das generische HTTP-Modul von OpenWB  Diese Methode beschreibe ich nicht, weil sie mehr Overhead erzeugt und seitens FHEM die Einrichtung eines CSRF-Token-freien Web-Kanals erfordert&lt;br /&gt;
* &#039;&#039;&#039;MQTT&#039;&#039;&#039;-Push durch FHEM zur OpenWB  Diese Methode erscheint mir vorteilhafter, weil auf einer stehenden TCP-Verbindung lediglich Meßwerte gepusht werden.&lt;br /&gt;
&lt;br /&gt;
=== Implementierung ===&lt;br /&gt;
&lt;br /&gt;
==== Vorbereitung ====&lt;br /&gt;
In der OpenWB-Web-UI unter Modulkonfiguration die entsprechenden Module (EVU, PV, Batterie) auf MQTT stellen. Hinweis: Nicht alle dabei erscheinenden MQTT-Topics müssen mit Werten beliefert werden! Sowohl bei der EVU-Schnittstelle wie bei PV reichen Momentanleistung und Zählerstände für eine zufriedenstellende Anbindung!&lt;br /&gt;
&lt;br /&gt;
==== Definition der OpenWB als MQTT-Target ====&lt;br /&gt;
 defmod openwb_mqtt MQTT2_CLIENT &amp;lt;ip-der-openwb&amp;gt;:1883&lt;br /&gt;
 attr openwb_mqtt autocreate simple&lt;br /&gt;
 attr openwb_mqtt subscriptions openWB/lp/1/#&lt;br /&gt;
&lt;br /&gt;
==== Übertragung der EVU-Meßwerte ====&lt;br /&gt;
In diesem Beispiel heißt das die Stromzählerdaten liefernde Device am OBIS-Modul &amp;quot;MT175&amp;quot;. Die Zahlen werden per Notify von diesem Device auf MQTT kopiert:&lt;br /&gt;
 defmod openwb_evu_cons notify MT175:total_consumption:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/WhImported &amp;quot; . $EVTPART1); }&lt;br /&gt;
 defmod openwb_evu_feed notify MT175:total_feed:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/WhExported &amp;quot; . $EVTPART1); }&lt;br /&gt;
 defmod openwb_evu_w notify MT175:power:.* { fhem(&amp;quot;set openwb_mqtt publish openWB/set/evu/W &amp;quot; . int($EVTPART1)); }&lt;br /&gt;
&lt;br /&gt;
==== Übertragung der PV-Meßwerte ====&lt;br /&gt;
Sofern die Daten für Momentanleistung und Zählerstand direkt in einem Device vorliegen, können analoge Notifys für dieses Device implementiert werden. Die Zielwerte lauten:&lt;br /&gt;
* Für den Momentan-Leistungswert &amp;lt;code&amp;gt;openWB/set/pv/1/W&amp;lt;/code&amp;gt;&lt;br /&gt;
* Für den Zählerstand &amp;lt;code&amp;gt;openWB/set/pv/1/WhCounter&amp;lt;/code&amp;gt;&lt;br /&gt;
Dabei muss beachtet werden, dass - wie bei der EVU-Schnittstelle - nur Integerwerte für die Momentanleistung übertragen werden dürfen.&lt;br /&gt;
&lt;br /&gt;
==== Anbindung an Alexa ====&lt;br /&gt;
Der generische Smarthome-Skill &amp;quot;FHEMConnector&amp;quot; erlaubt nur die leider immer noch sehr limitierte Syntax von Amazon Alexa. Im Folgenden werden die Definitionen für die Befehle:&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen ein&amp;quot;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen aus&amp;quot;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&amp;quot;Alexa, schalte Überschussladen auf 6 (Prozent)&amp;quot;&#039;&#039;&lt;br /&gt;
dargestellt. &amp;quot;Überschussladen auf 6&amp;quot; bedeutet dabei real den &amp;quot;Min+PV&amp;quot;, also Überschussladen mit Minimalleistung von 6 Ampere. Je nach Tagesform von Amazon ist dabei das Sprechen von &amp;quot;Prozent&amp;quot; nötig, auch wenn dies natürlich sachlich falsch ist.&lt;br /&gt;
 define openwb_ueberschuss dummy&lt;br /&gt;
 attr openwb_ueberschuss alexaName Überschussladen&lt;br /&gt;
 attr openwb_ueberschuss genericDeviceType light&lt;br /&gt;
 attr openwb_ueberschuss readingList pct&lt;br /&gt;
 attr openwb_ueberschuss setList on off pct&lt;br /&gt;
 define openwb_ueberschuss_on notify openwb_ueberschuss:on set openwb_mqtt publish openWB/set/ChargeMode 2&lt;br /&gt;
 define openwb_ueberschuss_off notify openwb_ueberschuss:off set openwb_mqtt publish openWB/set/ChargeMode 3&lt;br /&gt;
 define openwb_ueberschuss_pct notify openwb_ueberschuss:pct:.* set openwb_mqtt publish openWB/config/set/pv/minCurrentMinPv $EVTPART1 ;; set openwb_mqtt publish openWB/set/ChargeMode 1&lt;br /&gt;
&lt;br /&gt;
==Anwendungs Beispiele==&lt;br /&gt;
===Komplexe Anbindung===&lt;br /&gt;
[[Bild:Kia.PNG|mini|700px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
Hier mal ein Beispiel mit weiteren Schnittstellen in der Haussteuerung. Im Hintergrund arbeitet ein Wechselrichter Schwarm mit einem Hausspeicher, der beim BEV Laden gesperrt wird. Die openWB kommuniziert direkt mit den zwei Kostal Wechselrichtern, dem KSEM und dem am Master angeschlossenen Speicher. Das BEV ist über Kia Connect angebunden.&lt;br /&gt;
[[Bild:WB_1.PNG|mini|700px|rechts|openWB mit Statistiken]]&lt;br /&gt;
[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss, inklusive Wechselrichter, raus kommen. Die openWBs sind unten links.]]&lt;br /&gt;
====Verwendete Schnittstellen / Devices====&lt;br /&gt;
=====openWB MQTT=====&lt;br /&gt;
Wie oben beschrieben mit folgender MQTT definition. Im Bild ist das DOIF dargestellt und das MQTT Device als kurze Darstellung unterhalb der Tabelle. Das MQTT wird nur zur Kopplung verwendet, hat jedoch jetzt auch ein stateFormat inklusieve Statistiken erhalten.&lt;br /&gt;
&lt;br /&gt;
RAW des MQTT Device&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WB_1 MQTT2_DEVICE WB_1_MQTT2&lt;br /&gt;
attr WB_1 DbLogExclude .*&lt;br /&gt;
attr WB_1 DbLogInclude lp_1_.*,.*AllChargePoints.*,ChargeMode&lt;br /&gt;
attr WB_1 IODev WB_1_MQTT2&lt;br /&gt;
attr WB_1 alias WB_1&lt;br /&gt;
attr WB_1 autocreate 0&lt;br /&gt;
attr WB_1 comment Die openWB besteht aus zwei Ladepunkten.&lt;br /&gt;
attr WB_1 devicetopic openWB&lt;br /&gt;
attr WB_1 disable 0&lt;br /&gt;
attr WB_1 event-on-change-reading lp_1_.*,.*AllChargePoints.*,ChargeMode&lt;br /&gt;
attr WB_1 group PV Eigenverbrauch&lt;br /&gt;
attr WB_1 icon fuel&lt;br /&gt;
attr WB_1 readingList $DEVICETOPIC/global/WHouseConsumption:.* WHouseConsumption\&lt;br /&gt;
$DEVICETOPIC/global/WAllChargePoints:.* WAllChargePoints\&lt;br /&gt;
$DEVICETOPIC/global/ChargeMode:.* {my %h=(0=&amp;gt;&#039;SofortLaden&#039;,1=&amp;gt;&#039;MinPV&#039;,2=&amp;gt;&#039;NurPV&#039;,3=&amp;gt;&#039;Stop&#039;,4=&amp;gt;&#039;Standby&#039;);; return {ChargeMode=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/global/awattar/boolAwattarEnabled:.* boolAwattarEnabled\&lt;br /&gt;
$DEVICETOPIC/global/awattar/ActualPriceForCharging:.* ActualPriceForCharging\&lt;br /&gt;
$DEVICETOPIC/global/awattar/MaxPriceForCharging:.* MaxPriceForCharging\&lt;br /&gt;
$DEVICETOPIC/global/boolRse:.* boolRse\&lt;br /&gt;
$DEVICETOPIC/global/DailyYieldAllChargePointsKwh:.* DailyYieldAllChargePointsKwh\&lt;br /&gt;
$DEVICETOPIC/global/rfidConfigured:.* rfidConfigured\&lt;br /&gt;
$DEVICETOPIC/global/kWhCounterAllChargePoints:.* kWhCounterAllChargePoints\&lt;br /&gt;
$DEVICETOPIC/global/strLastmanagementActive:.* strLastmanagementActive\&lt;br /&gt;
$DEVICETOPIC/global/ETProvider/modulePath:.* modulePath\&lt;br /&gt;
$DEVICETOPIC/global/cpuTemp:.* cpuTemp\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/system/Uptime:.* Uptime\&lt;br /&gt;
$DEVICETOPIC/system/Date:.* Date\&lt;br /&gt;
$DEVICETOPIC/system/Timestamp:.* Timestamp\&lt;br /&gt;
$DEVICETOPIC/system/Version:.* Version\&lt;br /&gt;
$DEVICETOPIC/system/IpAddress:.* IpAddress\&lt;br /&gt;
$DEVICETOPIC/system/lastRfId:.* lastRfId\&lt;br /&gt;
$DEVICETOPIC/system/updateInProgress:.* updateInProgress\&lt;br /&gt;
$DEVICETOPIC/system/ConfiguredChargePoints:.* ConfiguredChargePoints\&lt;br /&gt;
$DEVICETOPIC/system/lastlivevalues:.* lastlivevalues\&lt;br /&gt;
$DEVICETOPIC/system/randomSleep:.* randomSleep\&lt;br /&gt;
$DEVICETOPIC/system/wizzardDone:.* wizzardDone\&lt;br /&gt;
$DEVICETOPIC/system/priceForKWh:.* priceForKWh\&lt;br /&gt;
$DEVICETOPIC/system/reloadDisplay:.* reloadDisplay\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/evu/ASchieflast:.* ASchieflast\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/P%Soc:.* lp_1_Pct_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/1/%Soc:.* lp_1_current_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/1/\x25Soc:.* lp_1__Soc\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/countPhasesInUse:.* lp_1_countPhasesInUse\&lt;br /&gt;
$DEVICETOPIC/lp/1/ChargePointEnabled:.* lp_1_ChargePointEnabled\&lt;br /&gt;
$DEVICETOPIC/lp/1/ChargeStatus:.* lp_1_ChargeStatus\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhDailyCharged:.* lp_1_kWhDailyCharged\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhCounter:.* lp_1_kWhCounter\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhActualCharged:.* lp_1_kWhActualCharged\&lt;br /&gt;
$DEVICETOPIC/lp/1/kWhChargedSincePlugged:.* lp_1_kWhChargedSincePlugged\&lt;br /&gt;
$DEVICETOPIC/lp/1/energyConsumptionPer100km:.* lp_1_energyConsumptionPer100km\&lt;br /&gt;
$DEVICETOPIC/lp/1/kmCharged:.* lp_1_kmCharged\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/strChargePointName:.* lp_1_strChargePointName\&lt;br /&gt;
$DEVICETOPIC/lp/1/TimeRemaining:.* lp_1_TimeRemaining\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase2:.* lp_1_PfPhase2\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase3:.* lp_1_PfPhase3\&lt;br /&gt;
$DEVICETOPIC/lp/1/PfPhase1:.* lp_1_PfPhase1\&lt;br /&gt;
$DEVICETOPIC/lp/1/W:.* lp_1_W\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolPlugStat:.* {my %h=(0=&amp;gt;&#039;no Plug&#039;,1=&amp;gt;&#039;Plugged in&#039;);; return {lp_1_PlugStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargeStat:.* {my %h=(0=&amp;gt;&#039;not loading&#039;,1=&amp;gt;&#039;loading&#039;);; return {lp_1_ChargeStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/1/AConfigured:.* lp_1_AConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargePointConfigured:.* lp_1_boolChargePointConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolSocConfigured:.* lp_1_boolSocConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolDirectModeChargekWh:.* lp_1_boolDirectModeChargekWh\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolDirectChargeModeSoc:.* lp_1_boolDirectChargeModeSoc\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolFinishAtTimeChargeActive:.* lp_1_boolFinishAtTimeChargeActive\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolChargeAtNight:.* lp_1_boolChargeAtNight\&lt;br /&gt;
$DEVICETOPIC/lp/1/boolSocManual:.* lp_1_boolSocManual\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/AutolockStatus:.* lp_1_AutolockStatus\&lt;br /&gt;
$DEVICETOPIC/lp/1/AutolockConfigured:.* lp_1_AutolockConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/1/lastRfId:.* lp_1_lastRfId\&lt;br /&gt;
$DEVICETOPIC/lp/1/pluggedladungakt:.* lp_1_pluggedladungakt\&lt;br /&gt;
$DEVICETOPIC/lp/1/plugStartkWh:.* lp_1_plugStartkWh\&lt;br /&gt;
$DEVICETOPIC/lp/1/MeterSerialNumber:.* lp_1_MeterSerialNumber\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/P%Soc:.* lp_2_Pct_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/2/%Soc:.* lp_2_current_Soc\&lt;br /&gt;
$DEVICETOPIC/lp/2/\x25Soc:.* lp_2__Soc\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/countPhasesInUse:.* lp_2_countPhasesInUse\&lt;br /&gt;
$DEVICETOPIC/lp/2/ChargePointEnabled:.* lp_2_ChargePointEnabled\&lt;br /&gt;
$DEVICETOPIC/lp/2/ChargeStatus:.* lp_2_ChargeStatus\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhDailyCharged:.* lp_2_kWhDailyCharged\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhCounter:.* lp_2_kWhCounter\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhActualCharged:.* lp_2_kWhActualCharged\&lt;br /&gt;
$DEVICETOPIC/lp/2/kWhChargedSincePlugged:.* lp_2_kWhChargedSincePlugged\&lt;br /&gt;
$DEVICETOPIC/lp/2/energyConsumptionPer100km:.* lp_2_energyConsumptionPer100km\&lt;br /&gt;
$DEVICETOPIC/lp/2/kmCharged:.* lp_2_kmCharged\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/strChargePointName:.* lp_2_strChargePointName\&lt;br /&gt;
$DEVICETOPIC/lp/2/TimeRemaining:.* lp_2_TimeRemaining\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/W:.* lp_2_W\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolPlugStat:.* {my %h=(0=&amp;gt;&#039;no Plug&#039;,1=&amp;gt;&#039;Plugged in&#039;);; return {lp_2_PlugStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargeStat:.* {my %h=(0=&amp;gt;&#039;not loading&#039;,1=&amp;gt;&#039;loading&#039;);; return {lp_2_ChargeStat=&amp;gt;$h{$EVENT}}}\&lt;br /&gt;
$DEVICETOPIC/lp/2/AConfigured:.* lp_2_AConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargePointConfigured:.* lp_2_boolChargePointConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolSocConfigured:.* lp_2_boolSocConfigured\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolDirectModeChargekWh:.* lp_2_boolDirectModeChargekWh\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolDirectChargeModeSoc:.* lp_2_boolDirectChargeModeSoc\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolFinishAtTimeChargeActive:.* lp_2_boolFinishAtTimeChargeActive\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolChargeAtNight:.* lp_2_boolChargeAtNight\&lt;br /&gt;
$DEVICETOPIC/lp/2/boolSocManual:.* lp_2_boolSocManual\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/AutolockStatus:.* lp_2_AutolockStatus\&lt;br /&gt;
$DEVICETOPIC/lp/2/AutolockConfigured:.* lp_2_AutolockConfigured\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/lp/2/lastRfId:.* lp_2_lastRfId\&lt;br /&gt;
$DEVICETOPIC/lp/2/pluggedladungakt:.* lp_2_pluggedladungakt\&lt;br /&gt;
$DEVICETOPIC/lp/2/plugStartkWh:.* lp_2_plugStartkWh\&lt;br /&gt;
$DEVICETOPIC/lp/2/MeterSerialNumber:.* lp_2_MeterSerialNumber\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_direct:.* boolChargeAtNight_direct\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_nurpv:.* boolChargeAtNight_nurpv\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_minpv:.* boolChargeAtNight_minpv\&lt;br /&gt;
$DEVICETOPIC/boolDisplayHouseConsumption:.* boolDisplayHouseConsumption\&lt;br /&gt;
$DEVICETOPIC/boolDisplayDailyCharged:.* boolDisplayDailyCharged\&lt;br /&gt;
$DEVICETOPIC/boolEvuSmoothedActive:.* boolEvuSmoothedActive\&lt;br /&gt;
$DEVICETOPIC/pv/bool70PVDynActive:.* bool70PVDynActive\&lt;br /&gt;
$DEVICETOPIC/pv/W70PVDyn:.* W70PVDyn\&lt;br /&gt;
$DEVICETOPIC/pv/bool70PVDynStatus:.* bool70PVDynStatus\&lt;br /&gt;
$DEVICETOPIC/pv/CounterTillStartPvCharging:.* CounterTillStartPvCharging\&lt;br /&gt;
$DEVICETOPIC/pv/W:.* W\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/nurpv70dynact:.* nurpv70dynact\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/nurpv70dynw:.* nurpv70dynw\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/priorityModeEVBattery:.* priorityModeEVBattery\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minSocAlwaysToChargeTo:.* lp_1_minSocAlwaysToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/maxSoc:.* lp_1_maxSoc\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minSocAlwaysToChargeToCurrent:.* lp_1_minSocAlwaysToChargeToCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/maxSocToChargeTo:.* lp_1_maxSocToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/minCurrent:.* lp_1_minCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/1/socLimitation:.* lp_1_socLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/minCurrent:.* lp_2_minCurrent\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/maxSoc:.* lp_2_maxSoc\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/lp/2/socLimitation:.* lp_2_socLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/socStopChargeAtMinPv:.* socStopChargeAtMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/regulationPoint:.* regulationPoint\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minBatteryDischargeSocAtBattPriority:.* minBatteryDischargeSocAtBattPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minBatteryChargePowerAtEvPriority:.* minBatteryChargePowerAtEvPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minFeedinPowerBeforeStart:.* minFeedinPowerBeforeStart\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/boolAdaptiveCharging:.* boolAdaptiveCharging\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/adaptiveChargingFactor:.* adaptiveChargingFactor\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/batteryDischargePowerAtBattPriority:.* batteryDischargePowerAtBattPriority\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/boolShowPriorityIconInTheme:.* boolShowPriorityIconInTheme\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/maxPowerConsumptionBeforeStop:.* maxPowerConsumptionBeforeStop\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/stopDelay:.* stopDelay\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/chargeSubmode:.* chargeSubmode\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/minCurrentMinPv:.* minCurrentMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/socStartChargeAtMinPv:.* socStartChargeAtMinPv\&lt;br /&gt;
$DEVICETOPIC/config/get/pv/startDelay:.* startDelay\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/energyToCharge:.* lp_2_energyToCharge\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/chargeLimitation:.* lp_2_chargeLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/socToChargeTo:.* lp_2_socToChargeTo\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/2/current:.* lp_2_current\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/socToChargeTo:.* lp_1_socToChargeTo\&lt;br /&gt;
\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/energyToCharge:.* lp_1_energyToCharge\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/chargeLimitation:.* lp_1_chargeLimitation\&lt;br /&gt;
$DEVICETOPIC/config/get/sofort/lp/1/current:.* lp_1_current\&lt;br /&gt;
$DEVICETOPIC/config/get/global/minEVSECurrentAllowed:.* minEVSECurrentAllowed\&lt;br /&gt;
$DEVICETOPIC/config/get/global/maxEVSECurrentAllowed:.* maxEVSECurrentAllowed\&lt;br /&gt;
$DEVICETOPIC/config/get/global/dataProtectionAcknoledged:.* dataProtectionAcknoledged\&lt;br /&gt;
$DEVICETOPIC/config/get/global/slaveMode:.* slaveMode\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/standbyPhases:.* standbyPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/sofortPhases:.* sofortPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/nachtPhases:.* nachtPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/minundpvPhases:.* minundpvPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/nurpvPhases:.* nurpvPhases\&lt;br /&gt;
$DEVICETOPIC/config/get/u1p3p/isConfigured:.* isConfigured\&lt;br /&gt;
$DEVICETOPIC/boolChargeAtNight_standby:.* boolChargeAtNight_standby\&lt;br /&gt;
$DEVICETOPIC/set/system/reloadDisplay:.* reloadDisplay\&lt;br /&gt;
$DEVICETOPIC/set/system/topicSender:.* topicSender\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/faultState:.* lp_2_faultState\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/faultStr:.* lp_2_faultStr\&lt;br /&gt;
$DEVICETOPIC/set/lp/2/ChargePointEnabled:.* lp_2_ChargePointEnabled&lt;br /&gt;
attr WB_1 room MQTT2_DEVICE,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WB_1 setList Lademodus:SofortLaden,Min+PV,NurPV,Stop,Standby { my %h=(SofortLaden=&amp;gt;&#039;0&#039;,&#039;Min+PV&#039;=&amp;gt;&#039;1&#039;,NurPV=&amp;gt;&#039;2&#039;,Stop=&amp;gt;&#039;3&#039;,Standby=&amp;gt;&#039;4&#039;);;qq($DEVICETOPIC/set/ChargeMode $h{$EVTPART1}) }\&lt;br /&gt;
DirectChargeSubMode:Aus,kWh_Laden,SoC_Laden { my %h=(Aus=&amp;gt;&#039;0&#039;,kWh_Laden=&amp;gt;&#039;1&#039;,SoC_Laden=&amp;gt;&#039;2&#039;);;qq($DEVICETOPIC/set/lp1/DirectChargeSubMode $h{$EVTPART1}) }\&lt;br /&gt;
lp_1_socToChargeTo:50,60,70,80,90,100 { qq($DEVICETOPIC/config/set/sofort/lp/1/socToChargeTo $EVTPART1) }&lt;br /&gt;
attr WB_1 sortby 311&lt;br /&gt;
attr WB_1 stateFormat {\&lt;br /&gt;
 my $YearBefore=&#039;LogDBRep_Statistic_previous_Year&#039;;;\&lt;br /&gt;
 my $DUMMY  = &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $date = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;lastlivevalues&amp;quot;,0))));;\&lt;br /&gt;
\&lt;br /&gt;
 my $ChargeMode          = ReadingsVal($name,&amp;quot;ChargeMode&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
    $ChargeMode          = ($ChargeMode eq &amp;quot;SofortLaden&amp;quot;)? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;SofortLaden&amp;lt;/span&amp;gt;&amp;quot; : ($ChargeMode eq &amp;quot;MinPV&amp;quot;)?  &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Min+PV&amp;lt;/span&amp;gt;&amp;quot; : ($ChargeMode eq &amp;quot;NurPV&amp;quot;)?  &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;NurPV&amp;lt;/span&amp;gt;&amp;quot; : $ChargeMode;;\&lt;br /&gt;
 \&lt;br /&gt;
 my $lp_1_Name           = ReadingsVal($name,&amp;quot;lp_1_strChargePointName&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_1_Power          = ReadingsVal($name,&amp;quot;lp_1_W&amp;quot;,0).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_1        = ReadingsVal($name,&amp;quot;lp_1_countPhasesInUse&amp;quot;,0).&amp;quot;P &amp;quot;.ReadingsVal($name,&amp;quot;lp_1_AConfigured&amp;quot;,0).&amp;quot;A&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Status_1       = ReadingsVal($name,&amp;quot;lp_1_PlugStat&amp;quot;,&amp;quot;n/a&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_1_ChargeStat&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_1_Status_2       = ReadingsVal($name,&amp;quot;lp_1_TimeRemaining&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_1_Power_d        = ReadingsVal($name,&amp;quot;lp_1_kWhDailyCharged&amp;quot;,0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_m        = round(ReadingsVal($name,&amp;quot;lp_1_kWhCounter_Month&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_1_Power_j        = sprintf(&amp;quot;%04d / %04d&amp;quot;,ReadingsVal($name,&amp;quot;lp_1_kWhCounter_Year&amp;quot;,0),ReadingsVal($YearBefore,&amp;quot;lp_1_kWhCounter_Year&amp;quot;,0));;\&lt;br /&gt;
 my $lp_1_Power_t        = round(ReadingsVal($name,&amp;quot;lp_1_kWhCounter&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_2_Name           = ReadingsVal($name,&amp;quot;lp_2_strChargePointName&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_2_Power          = ReadingsVal($name,&amp;quot;lp_2_W&amp;quot;,0).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_1        = ReadingsVal($name,&amp;quot;lp_2_countPhasesInUse&amp;quot;,0).&amp;quot;P &amp;quot;.ReadingsVal($name,&amp;quot;lp_2_AConfigured&amp;quot;,0).&amp;quot;A&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Status_1       = ReadingsVal($name,&amp;quot;lp_2_PlugStat&amp;quot;,&amp;quot;n/a&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_2_ChargeStat&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
 my $lp_2_Status_2       = &amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;lp_2_TimeRemaining&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
 my $lp_2_Power_d        = ReadingsVal($name,&amp;quot;lp_2_kWhDailyCharged&amp;quot;,0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_m        = round(ReadingsVal($name,&amp;quot;lp_2_kWhCounter_Month&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $lp_2_Power_j        = sprintf(&amp;quot;%04d / %04d&amp;quot;,ReadingsVal($name,&amp;quot;lp_2_kWhCounter_Year&amp;quot;,0),ReadingsVal($YearBefore,&amp;quot;lp_2_kWhCounter_Year&amp;quot;,0));;\&lt;br /&gt;
 my $lp_2_Power_t        = round(ReadingsVal($name,&amp;quot;lp_2_kWhCounter&amp;quot;,0),0).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Wallbox&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;$ChargeMode&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Status&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;Restladezeit&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;Leistung&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_1_Name.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Status_1.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Status_2.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_1.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$lp_1_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_2_Name.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Status_1.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Status_2.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_1.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$lp_2_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Statistik vom $date&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;aktuell&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Jahr/Vorjahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_1_Name.&amp;quot;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_d.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_m.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_1_Power_j.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;&amp;amp;nbsp;;&amp;amp;nbsp;;&amp;quot;.$lp_2_Name.&amp;quot;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_d.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_m.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$lp_2_Power_j.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr WB_1 userReadings lp_1_kWhCounter_Month:lp_1_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter_init_Month&amp;quot;,0),0) },\&lt;br /&gt;
lp_1_kWhCounter_Year:lp_1_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_1_kWhCounter_init_Year&amp;quot;,0),0)  },\&lt;br /&gt;
\&lt;br /&gt;
lp_2_kWhCounter_Month:lp_2_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter_init_Month&amp;quot;,0),0) },\&lt;br /&gt;
lp_2_kWhCounter_Year:lp_2_kWhCounter.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;lp_2_kWhCounter_init_Year&amp;quot;,0),0)  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia connect MQTT=====&lt;br /&gt;
Das Kia_connect Device empfängt und sendet die MQTT Nachrichten zum Node-red Flow für das Kia BEV.&lt;br /&gt;
&lt;br /&gt;
RAW des Kia connect&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Kia_connect MQTT2_DEVICE&lt;br /&gt;
attr Kia_connect DbLogExclude .*&lt;br /&gt;
attr Kia_connect DbLogInclude .*&lt;br /&gt;
attr Kia_connect IODev MQTT2_FHEM_Server&lt;br /&gt;
attr Kia_connect alias Kia_connect&lt;br /&gt;
attr Kia_connect autocreate 1&lt;br /&gt;
attr Kia_connect devicetopic bluelinky&lt;br /&gt;
attr Kia_connect group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Kia_connect icon car&lt;br /&gt;
attr Kia_connect readingList $DEVICETOPIC/status:.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/location.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/odometer:.* { json2nameValue($EVENT) }\&lt;br /&gt;
$DEVICETOPIC/req_received:.* req_received\&lt;br /&gt;
$DEVICETOPIC/req_active:.* req_active&lt;br /&gt;
attr Kia_connect room MQTT2_DEVICE,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Kia_connect setList getOdometer req/$DEVICETOPIC/get_odometer get_odometer\&lt;br /&gt;
getStatus req/$DEVICETOPIC/get_status get_status\&lt;br /&gt;
getLocation req/$DEVICETOPIC/get_location get_location\&lt;br /&gt;
getTripinfo req/$DEVICETOPIC/get_tripinfo\&lt;br /&gt;
getAll req/$DEVICETOPIC/get_all get_all\&lt;br /&gt;
setChargeTargetSoc req/$DEVICETOPIC/set_chargetargets\&lt;br /&gt;
startCharge req/$DEVICETOPIC/start_charging start_charging\&lt;br /&gt;
stopCharge req/$DEVICETOPIC/stop_charging stop_charging\&lt;br /&gt;
stopClimate req/$DEVICETOPIC/stop_climate stop_climate\&lt;br /&gt;
startClimate req/$DEVICETOPIC/start_climate&lt;br /&gt;
attr Kia_connect sortby 402&lt;br /&gt;
attr Kia_connect stateFormat req_active&lt;br /&gt;
attr Kia_connect userReadings atHomeStanding:location.* { ((abs(AttrVal(&amp;quot;global&amp;quot;,&amp;quot;latitude&amp;quot;,49.85) - ReadingsVal($NAME,&amp;quot;location_coord_lat&amp;quot;,0)) &amp;lt;= 0.001) &amp;amp;&amp;amp; (abs(AttrVal(&amp;quot;global&amp;quot;,&amp;quot;longitude&amp;quot;,8.49) - ReadingsVal($NAME,&amp;quot;location_coord_lon&amp;quot;,0)) &amp;lt;= 0.001) &amp;amp;&amp;amp; (ReadingsVal($NAME,&amp;quot;location_speed_value&amp;quot;,1) == 0)) ? &#039;true&#039; : &#039;false&#039;;;;; },\&lt;br /&gt;
batSOC:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_batteryStatus&amp;quot;,0);;;;},\&lt;br /&gt;
connected:status.* { (ReadingsVal($NAME,&amp;quot;status_evStatus_batteryPlugin&amp;quot;,0) != 0) ? &#039;true&#039; : &#039;false&#039;;;;;},\&lt;br /&gt;
charging:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_batteryCharge&amp;quot;,&#039;false&#039;);;;;},\&lt;br /&gt;
targetSOC:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel&amp;quot;,0);;;;},\&lt;br /&gt;
time2targetSOC:status.* { my $t = ReadingsVal($NAME,&amp;quot;status_evStatus_remainTime2_atc_value&amp;quot;,1);;;; sprintf(&amp;quot;%02d:%02d&amp;quot;, $t/60%60, $t%60);;},\&lt;br /&gt;
range:status.* { ReadingsVal($NAME,&amp;quot;status_evStatus_drvDistance_1_rangeByFuel_totalAvailableRange_value&amp;quot;,0);;;;},\&lt;br /&gt;
bat12v:status.* { ReadingsVal($NAME,&amp;quot;status_battery_batSoc&amp;quot;,0);;;;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Node-red=====&lt;br /&gt;
[[Bild:Kia Flow.PNG|mini|900px|rechts|Node-red Kia Flow]]&lt;br /&gt;
Node-red habe ich einfach in einem Docker Container runter geladen und gestartet. Über Port 1880 kommt man direkt in die GUI und kann den ersten Flow laden.&lt;br /&gt;
&lt;br /&gt;
docker-compose .yml Eintrag&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
  node-red:&lt;br /&gt;
    image: nodered/node-red:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
    environment:&lt;br /&gt;
      - TZ=Europe/Berlin&lt;br /&gt;
    ports:&lt;br /&gt;
      - 1880:1880&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./node-red/data:/data&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Danach fehlt im Container noch folgende Erweiterung für den Node-red Flow&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
npm install node-red-contrib-bluelinky&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia Connect=====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Kia connect ist eine API für Kia und Hyundai E-Autos mit der man Daten vom Auto abfragen kann und auch einige Steuerungen möglich sind.&lt;br /&gt;
Mit Node-red und BlueLinky wird die Schnittstelle bedient.&lt;br /&gt;
Der Flow ist nicht ursprünglich von mir, wurde jedoch noch erweitert.&lt;br /&gt;
Vor dem Laden des Flows sind noch die persönlichen Verbindungsdaten im JSON einzutragen.&lt;br /&gt;
&lt;br /&gt;
Nach dem Laden ist ein Test mit den Inject Symbolen und der Debug Funktionalität möglich und auch sinnvoll.&lt;br /&gt;
Unterhalb der MQTT - und BlueLinky Symbole sollte &amp;quot;Verbunden&amp;quot; oder &amp;quot;Ready&amp;quot; erscheinen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wichtig beim Kia ist, dass für das Laden über die openWB als SOC Ziel 80% im standard Modus konfiguriert wird.&#039;&#039;&#039; Ansonsten wundert man sich warum das Laden einfach nicht starten möchte. Im Default ist dort bei mir nur 50% eingetragen gewesen :-). Mit jetzt 100% kann die openWB auch selber einen Ziel SOC bestimmen, ansonsten hört das BEV einfach selber auf zu laden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin sollte man darauf achten, dass man nur eine begrenzte Anzahl von Nachrichten mit dem Kia BEV pro Tag austauschen kann. Das wurde im DOIF schon etwas berücksichtigt (1x pro Stunde), kann jedoch bei gleichzeitiger Verwendung der Handy App oder der SOC Abfrage im openWB Kia Modul auch mal zu Fehlern führen. Durch die Stündliche Status Abfrage im DOIF kommt es natürlich zu Verzögerungen im FHEM Status. Dann einfach einmal Manuell abfragen.&lt;br /&gt;
&lt;br /&gt;
Node-red JSON Import&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
[    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;tab&amp;quot;,&lt;br /&gt;
        &amp;quot;label&amp;quot;: &amp;quot;Kia e-Niro&amp;quot;,&lt;br /&gt;
        &amp;quot;disabled&amp;quot;: false,&lt;br /&gt;
        &amp;quot;info&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt-broker&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;mqtt_Server&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;&amp;lt;FHEM MQTT IP Adresse&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;port&amp;quot;: &amp;quot;1883&amp;quot;,&lt;br /&gt;
        &amp;quot;clientid&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;autoConnect&amp;quot;: true,&lt;br /&gt;
        &amp;quot;usetls&amp;quot;: false,&lt;br /&gt;
        &amp;quot;compatmode&amp;quot;: false,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;: &amp;quot;4&amp;quot;,&lt;br /&gt;
        &amp;quot;keepalive&amp;quot;: &amp;quot;60&amp;quot;,&lt;br /&gt;
        &amp;quot;cleansession&amp;quot;: true,&lt;br /&gt;
        &amp;quot;birthTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;birthQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;birthPayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;birthMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;closeTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;closeQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;closePayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;closeMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;willTopic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;willQos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;willPayload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;willMsg&amp;quot;: {},&lt;br /&gt;
        &amp;quot;sessionExpiry&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;bluelinky&amp;quot;,&lt;br /&gt;
        &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Mail Adresse bei Kia&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Passwort&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;region&amp;quot;: &amp;quot;EU&amp;quot;,&lt;br /&gt;
        &amp;quot;pin&amp;quot;: &amp;quot;&amp;lt;Pin&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;vin&amp;quot;: &amp;quot;&amp;lt;VIN&amp;gt;&amp;quot;,&lt;br /&gt;
        &amp;quot;brand&amp;quot;: &amp;quot;kia&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;91a345fa.5757a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_status&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;15dfb508.c6497b&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5ad085b9.05739c&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/start_climate&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;b27d74de.38c808&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;15dfb508.c6497b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-status&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get status&amp;quot;,&lt;br /&gt;
        &amp;quot;dorefresh&amp;quot;: true,&lt;br /&gt;
        &amp;quot;parsed&amp;quot;: false,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;cccc9476.d56dd8&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;87abdd88.8ff4d&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get car odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;40d2361c.579588&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;31100f9a.40008&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;locationWrapper&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;location\&amp;quot;: msg.payload,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;libs&amp;quot;: [],&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1490,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;bea1d927.0f3908&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-location&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get car location&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;31100f9a.40008&amp;quot;,&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3c949d67.0d83b2&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_location&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;bea1d927.0f3908&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;cccc9476.d56dd8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;analyseStatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    let status = msg.payload;\n    status.airTemp.value = 14+(parseInt(status.airTemp.value,16)/2);\n    try{\n    status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    } catch(e) {}\n\n    let time = status.evStatus.remainTime2.atc.value/60;\n    let result = { \n                 \&amp;quot;batSOC\&amp;quot;: status.evStatus.batteryStatus,\n                 \&amp;quot;connected\&amp;quot;: (status.evStatus.batteryPlugin !== 0),\n                 \&amp;quot;charging\&amp;quot;: status.evStatus.batteryCharge,\n                 \&amp;quot;targetSOC\&amp;quot;: status.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,\n                 \&amp;quot;time2targetSOC\&amp;quot;: (Math.floor(time) + \&amp;quot;:\&amp;quot; + (\&amp;quot;0\&amp;quot; + Math.floor((time % 1)*60)).slice(-2)), // h:mm\n                 \&amp;quot;range\&amp;quot;: status.evStatus.drvDistance[0].rangeByFuel.totalAvailableRange.value,\n                 \&amp;quot;bat12v\&amp;quot;: status.battery.batSoc\n                };\n    \n    //msg.payload = result;\n    msg.payload = {\n        \&amp;quot;status\&amp;quot;: status,\n        \&amp;quot;error\&amp;quot;: false\n        \n    };\n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1480,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/location&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 120,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/status&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1900,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;844a32f4.2e029&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/stop_climate&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7d3ae860.d8c9a8&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;57d91e50.7e96&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/start_charging&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 820,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;6eebc52c.ee23dc&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;6029f0a0.b73e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/stop_charging&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 880,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;84a1ae.74912e5&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;c5ecf76c.e753c8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;start-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Start car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;6eebc52c.ee23dc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;start-charge&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Start Charging&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 820,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;84a1ae.74912e5&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;stop-charge&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Stop Charging&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 880,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7d3ae860.d8c9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;stop-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Stop car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;b27d74de.38c808&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;obj&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 680,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;c5ecf76c.e753c8&amp;quot;,&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;45a6a8e6.2abfd8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_odometer&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 280,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;87abdd88.8ff4d&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 930,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 920,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/req_received&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 860,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 480,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;1babee6c.1c2982&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_all&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;,&lt;br /&gt;
                &amp;quot;4375fbb9.00fb44&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1850,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1470,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;3f82a275.5a0b6e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 930,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;24d5e0b.3aafc2&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;change&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;rules&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;t&amp;quot;: &amp;quot;set&amp;quot;,&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
                &amp;quot;pt&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
                &amp;quot;to&amp;quot;: &amp;quot;pending&amp;quot;,&lt;br /&gt;
                &amp;quot;tot&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;from&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;to&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;reg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 790,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1140,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
                &amp;quot;fecad185.324f8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;change&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;rules&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;t&amp;quot;: &amp;quot;set&amp;quot;,&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
                &amp;quot;pt&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
                &amp;quot;to&amp;quot;: &amp;quot;idle&amp;quot;,&lt;br /&gt;
                &amp;quot;tot&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;from&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;to&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;reg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1910,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 760,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
                &amp;quot;fecad185.324f8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4dd1ea4a.52f144&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt out&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;bluelinky/req_active&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;retain&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 2140,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;fecad185.324f8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;false&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 2110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1160,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;40d2361c.579588&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;odometerWrapper&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    msg.payload = { \n        \&amp;quot;odometer\&amp;quot;: msg.payload,\n        \&amp;quot;error\&amp;quot;: false\n        };\n\n    return msg;\n}&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;libs&amp;quot;: [],&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1490,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 200,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
                &amp;quot;262df5dc.57916a&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;226ed925.607bb6&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1430,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 80,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4375fbb9.00fb44&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;car-fullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get full status&amp;quot;,&lt;br /&gt;
        &amp;quot;dorefresh&amp;quot;: true,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1120,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;226ed925.607bb6&amp;quot;,&lt;br /&gt;
                &amp;quot;69b6c4df.ea6bcc&amp;quot;,&lt;br /&gt;
                &amp;quot;89681a97.9e24d8&amp;quot;,&lt;br /&gt;
                &amp;quot;92dc3ff4.1d6e3&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;69b6c4df.ea6bcc&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;locationFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;location\&amp;quot;: msg.payload.vehicleLocation,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1500,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 360,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;85a07155.a0f9f&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;92dc3ff4.1d6e3&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;statusFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n    let status = msg.payload.vehicleStatus;\n    try{\n        status.airTemp.value = 14+(parseInt(status.airTemp.value,16)/2);\n        status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reservChargeInfo.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n        status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value = 14+(parseInt(status.evStatus.reservChargeInfos.reserveChargeInfo2.reservChargeInfoDetail.reservFatcSet.airTemp.value,16)/2);\n    } catch(e) {}\n\n    msg.payload = { \n        \&amp;quot;status\&amp;quot;: status,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1500,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 480,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;3efceea0.c81b12&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;89681a97.9e24d8&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;odometerFromFullstatus&amp;quot;,&lt;br /&gt;
        &amp;quot;func&amp;quot;: &amp;quot;if(msg.payload.hasOwnProperty(\&amp;quot;body\&amp;quot;)) {\n    msg.payload = {\&amp;quot;error\&amp;quot;:true};\n    return msg;\n}\nelse {\n\n    msg.payload = { \n        \&amp;quot;odometer\&amp;quot;: msg.payload.odometer,\n        \&amp;quot;error\&amp;quot;: false\n    };\n    \n    return msg;\n}\n&amp;quot;,&lt;br /&gt;
        &amp;quot;outputs&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;noerr&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;initialize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;finalize&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1510,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 420,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;327104fc.71e1bc&amp;quot;,&lt;br /&gt;
                &amp;quot;331e5860.907808&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;331e5860.907808&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1850,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 520,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;aa4d220b.f7e19&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;set-chargetargets&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Set charge targets&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4c03338d.2f15ec&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;login&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Login&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1090,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;28b868f5.16cb48&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;43200&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: true,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: &amp;quot;12&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 950,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1040,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4c03338d.2f15ec&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;db9ecdb5.a9683&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/set_chargetargets&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 290,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7064a8d53256b646&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;,&lt;br /&gt;
                &amp;quot;24d5e0b.3aafc2&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;44155ad70c47b0dd&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;15dfb508.c6497b&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7064a8d53256b646&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;obj&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 960,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;33b1bc85.662694&amp;quot;,&lt;br /&gt;
                &amp;quot;aa4d220b.f7e19&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;7064395e56292844&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 340,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;4375fbb9.00fb44&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5f9ff828080f5fe6&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;lock-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Lock car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 560,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;,&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;492f5b94a865e47b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 540,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;5f9ff828080f5fe6&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;d6f3f148e765caf9&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/car_lock&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 260,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 560,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;5f9ff828080f5fe6&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;cdc13a486db22b8e&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/car_unlock&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: false,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 620,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;99f5c3a41ac3e754&amp;quot;,&lt;br /&gt;
                &amp;quot;ce62ba4f.d86548&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;99f5c3a41ac3e754&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unlock-car&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Unlock car&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1110,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 620,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;f487d6d6.a4d568&amp;quot;,&lt;br /&gt;
                &amp;quot;811aa567.e89f98&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ab557a0ea621403a&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 600,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;99f5c3a41ac3e754&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;a525de86e4374518&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 740,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;7d3ae860.d8c9a8&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;0b8cb92c042fe140&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 800,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;6eebc52c.ee23dc&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;ae4c2139b08aaa28&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 860,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;84a1ae.74912e5&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;dd23108ce63f456d&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;get-monthlyreport&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Get monthly report&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1130,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;e57eb97531129426&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;a6e5e8deb52145f1&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;inject&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;props&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;payload&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;p&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
                &amp;quot;vt&amp;quot;: &amp;quot;str&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;repeat&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;crontab&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;once&amp;quot;: false,&lt;br /&gt;
        &amp;quot;onceDelay&amp;quot;: 0.1,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payload&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;payloadType&amp;quot;: &amp;quot;date&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 940,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1260,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;dd23108ce63f456d&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;95f1b6f32aafd65b&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;get-tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;bluelinky&amp;quot;: &amp;quot;452a3304.58c8fc&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1100,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;e57eb97531129426&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;fb2b99958bc48593&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;property&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;pretty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 750,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;95f1b6f32aafd65b&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;5230ebe391325b17&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: true,&lt;br /&gt;
        &amp;quot;rh&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;fb2b99958bc48593&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;e57eb97531129426&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;debug&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;active&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tosidebar&amp;quot;: true,&lt;br /&gt;
        &amp;quot;console&amp;quot;: false,&lt;br /&gt;
        &amp;quot;tostatus&amp;quot;: false,&lt;br /&gt;
        &amp;quot;complete&amp;quot;: &amp;quot;payload&amp;quot;,&lt;br /&gt;
        &amp;quot;targetType&amp;quot;: &amp;quot;msg&amp;quot;,&lt;br /&gt;
        &amp;quot;statusVal&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;statusType&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 1470,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1220,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: []&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;4fdf3b1b7811c89f&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;mqtt in&amp;quot;,&lt;br /&gt;
        &amp;quot;z&amp;quot;: &amp;quot;866c75dd.edd9a8&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: &amp;quot;req/bluelinky/get_tripinfo&amp;quot;,&lt;br /&gt;
        &amp;quot;qos&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
        &amp;quot;datatype&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
        &amp;quot;broker&amp;quot;: &amp;quot;bb13a99d.68b8f8&amp;quot;,&lt;br /&gt;
        &amp;quot;nl&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rap&amp;quot;: true,&lt;br /&gt;
        &amp;quot;rh&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;inputs&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 270,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 1280,&lt;br /&gt;
        &amp;quot;wires&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
                &amp;quot;dd23108ce63f456d&amp;quot;&lt;br /&gt;
            ]&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kia_eNiro_PV DOIF mit uiTable=====&lt;br /&gt;
Mit diesem DOIF Device werden folgende Funktionalitäten abgebildet:&lt;br /&gt;
Nun dann noch das DOIF mit dem uiTable für die Status Anzeige und die Steuerung über Pull Down Menüs.&lt;br /&gt;
&lt;br /&gt;
- Status Abfrage&lt;br /&gt;
     Status jede Stunde zwischen 6 und 23 Uhr (12V min 40%)&lt;br /&gt;
     Status beim Laden alle 15 Minuten (12V min 40%)&lt;br /&gt;
     Anzeige des Kilometerzählers&lt;br /&gt;
     Status des Fahrzeuges zu Hause / unterwegs und beim Laden&lt;br /&gt;
     Fahrzeug Auf/Zu&lt;br /&gt;
&lt;br /&gt;
- Klimatisierung über das Pull Down Menü&lt;br /&gt;
     unterschiedliche Temperaturen für Heizen und Kühlen&lt;br /&gt;
     Aktuelle Temperatur&lt;br /&gt;
     Heizen/Klima Ein/Aus&lt;br /&gt;
     Timer für zeitgesteuertes Klimatisieren für den Resttag oder den Nächsten Tag (vor der aktuellen Zeit)&lt;br /&gt;
     Klimatisierung über &amp;quot;Abfall&amp;quot; Kalender (es geht nur ein Termin pro Tag, dafür aber komfortabel über das Handy)&lt;br /&gt;
&lt;br /&gt;
- Komfort&lt;br /&gt;
     Reifen Überwachung&lt;br /&gt;
     Türen / Motorhaube / Kofferraum Überwachung&lt;br /&gt;
     12V Batterie anzeige, wenn der Ladezustand kleiner 40% ist erfolgt keine weitere Status Abfrage&lt;br /&gt;
&lt;br /&gt;
- ACCU Steuerung&lt;br /&gt;
    Setzen des Ziel SOC beim Standard Laden&lt;br /&gt;
    Start/Stop Laden&lt;br /&gt;
    Accu Stand und berechnete Restkilometer&lt;br /&gt;
&lt;br /&gt;
- Für openWB integratin im uiTable&lt;br /&gt;
    Wählen des Lademodus&lt;br /&gt;
    Vorrang EV oder Bat&lt;br /&gt;
    Sperren des Hausspeichers entweder manuell oder automatisch beim Laden. Der vorherige Zustand wird gespeichert&lt;br /&gt;
        Die Freigabe erfolgt über die Wechselrichter Implementierung, siehe dort [[Kostal_Plenticore_10_Plus#Externe_Speichersteuerung_.28ExternControl.29|&amp;quot;Externe Speicher Steuerung&amp;quot;]]&lt;br /&gt;
    Geschätzte Ladezeit&lt;br /&gt;
    Status Ladepunkt (Plug und Laden)&lt;br /&gt;
    Lade Status Phasen und Leistung   &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, die Kia connect Abfragen sind auf ca. 200 pro Tag von Kia limitiert! Durch die Stündliche Status Abfrage im DOIF kommt es natürlich zu Verzögerungen im FHEM Status. Dann einfach einmal manuell abfragen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Kommunikation zum Kia BEV ist manchmal sehr träge, z.B. kann eine Status Abfrage auch mal 3 Minuten dauern, deshalb wurde eine Verriegelung implementiert. Es wird ein Status pending/idle angezeigt. Nur wenn der Zustand &amp;quot;idel&amp;quot; ist, können weitere Abfragen gestartet werden. Läuft z.B. die Status Abfrage kann man ein weiteres Kommando anstarten, es wird jedoch erst abgesetzt, wenn das vorherige Kommando fertig ist. Solange bleibt im Pull Down Menü das neue Kommando stehen.&lt;br /&gt;
&lt;br /&gt;
RAW des DOIF&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Kia_eNiro_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Kia Connect Status Abfrage erfolgt mit MQTT2 ==&amp;gt; node-ret ==&amp;gt; Kia Connect\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_getAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (  ([+00:15] and                                                  ## alle 15 Minuten\&lt;br /&gt;
         [Kia_connect:atHomeStanding] eq &amp;quot;true&amp;quot; and                    ##   wenn das Auto zuhause ist\&lt;br /&gt;
         [Kia_connect:charging]       eq &amp;quot;true&amp;quot; or                     ##   und es geladen wird\&lt;br /&gt;
         [:58] and [05:00-23:00]                                       ## ansonsten nur jede Stunde\&lt;br /&gt;
        ) and [Kia_connect:bat12v] &amp;gt; 40                                ## aber die 12V Batterie sollte noch genügend Ladung haben\&lt;br /&gt;
      or [$SELF:cmd_event]  eq &amp;quot;set_cmd_1&amp;quot;                             ## Das reagiert auf den Aufruf mit &amp;quot;set &amp;lt;Device&amp;gt; cmd_*&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_getAll&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_getAll&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_before_1&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    fhem_set(&amp;quot;Kia_connect getAll&amp;quot;);;                                    ## beliebige Kommandos für diesen Block\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_Klima\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_2] eq &amp;quot;stopClimate&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;startHeating&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;startCooling&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_2&amp;quot;,[$SELF:ui_command_2]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;startHeating&amp;quot;) {\&lt;br /&gt;
      my $airTemp_value= [Kia_connect:status_airTemp_value_target_Winter];;\&lt;br /&gt;
      fhem_set(&#039;Kia_connect startClimate {&amp;quot;defrost&amp;quot;: true, &amp;quot;windscreenHeating&amp;quot;: true, &amp;quot;temperature&amp;quot;: &#039;.$airTemp_value.&#039; , &amp;quot;unit&amp;quot;: &amp;quot;C&amp;quot;}&#039;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : startHeating&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;startCooling&amp;quot;) {\&lt;br /&gt;
      my $airTemp_value = [Kia_connect:status_airTemp_value_target_Summer];;\&lt;br /&gt;
      fhem_set(&#039;Kia_connect startClimate {&amp;quot;defrost&amp;quot;: false, &amp;quot;windscreenHeating&amp;quot;: false, &amp;quot;temperature&amp;quot;: &#039;.$airTemp_value.&#039; , &amp;quot;unit&amp;quot;: &amp;quot;C&amp;quot;}&#039;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : startCooling&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    if ([$SELF:ui_command_2] eq &amp;quot;stopClimate&amp;quot;) {\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_2]);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 2_Klima       : stopClimate&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
    fhem_set(&amp;quot;Abfall update&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_Laden\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_3] eq &amp;quot;setChargeTargetSoc&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_3] eq &amp;quot;startCharge&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_3] eq &amp;quot;stopCharge&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_3&amp;quot;,[$SELF:ui_command_3]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_3] eq &amp;quot;setChargeTargetSoc&amp;quot;) {\&lt;br /&gt;
      my $targetSOClist_1_targetSOClevel = [Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_1_targetSOClevel_target];;\&lt;br /&gt;
      my $targetSOClist_2_targetSOClevel = [Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel_target];;\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect setChargeTargetSoc {\&amp;quot;fast\&amp;quot;: &amp;quot;.$targetSOClist_1_targetSOClevel.&amp;quot;, \&amp;quot;slow\&amp;quot;: &amp;quot;.$targetSOClist_2_targetSOClevel.&amp;quot;}&amp;quot;);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_3]);;                   ## beliebige Kommandos für diesen Block\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_3&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
4_Klima_timer_heizen\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       (    [[Abfall_Abfuhr:Kiaheizen_connect_time]]                   ## Prüfe den Kalender Eintrag\&lt;br /&gt;
        and [Abfall_Abfuhr:Kiaheizen_connect_date] eq $ymd             ##   ist es heute?\&lt;br /&gt;
       )\&lt;br /&gt;
       or\&lt;br /&gt;
       (    [$SELF:ui_timer_mode] eq &amp;quot;heizen&amp;quot;                          ## Timer zum Heizen aktiv?\&lt;br /&gt;
        and [[$SELF:ui_timer_Start]]                                   ##   ist es soweit?\&lt;br /&gt;
       )\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 4_Klima_timer : startHeating&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_timer_mode&amp;quot;,&amp;quot;Aus&amp;quot;);;                                ## Schalte die Timer Funktion ab\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;startHeating&amp;quot;);;                        ## Es soll geheizt werden\&lt;br /&gt;
    fhem_set(&amp;quot;$SELF 2_Klima&amp;quot;);;                                         ## Aktiviere das Heizen\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
5_Klima_timer_kuehlen\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       (    [[Abfall_Abfuhr:Kiakuehlen_connect_time]]                  ## Prüfe den Kalender Eintrag\&lt;br /&gt;
        and [Abfall_Abfuhr:Kiakuehlen_connect_date] eq $ymd            ##   ist es heute?\&lt;br /&gt;
       )\&lt;br /&gt;
       or\&lt;br /&gt;
       (    [$SELF:ui_timer_mode] eq &amp;quot;kuehlen&amp;quot;                         ## Timer zum Kühler aktiv?\&lt;br /&gt;
        and [[$SELF:ui_timer_Start]]                                   ##   ist es soweit?\&lt;br /&gt;
       )\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 4_Klima_timer : startCooling&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_timer_mode&amp;quot;,&amp;quot;Aus&amp;quot;);;                                ## Schalte die Timer Funktion ab\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;startCooling&amp;quot;);;                        ## Es soll gekühlt werden\&lt;br /&gt;
    fhem_set(&amp;quot;$SELF 2_Klima&amp;quot;);;                                         ## Aktiviere das Kühlen\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
6_Auf_Zu\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and [Kia_connect:req_active] eq &amp;quot;idle&amp;quot;\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_2] eq &amp;quot;car_lock&amp;quot;                            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_2] eq &amp;quot;car_unlock&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_2&amp;quot;,[$SELF:ui_command_2]);;\&lt;br /&gt;
\&lt;br /&gt;
    fhem_set(&amp;quot;Kia_connect &amp;quot;.[$SELF:ui_command_2]);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 6_Auf_Zu      : &amp;quot;.[$SELF:ui_command_2]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
7_WB_1_lp_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_4] eq &amp;quot;SofortLaden&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Min+PV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;NurPV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Stop&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Standby&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_4] eq &amp;quot;Vorrang_Bat&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_4&amp;quot;,[$SELF:ui_command_4]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_4] eq &amp;quot;Vorrang_Bat&amp;quot; or [$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;) {\&lt;br /&gt;
      if ([$SELF:ui_command_4] eq &amp;quot;Vorrang_EV&amp;quot;) {\&lt;br /&gt;
        fhem_set(&amp;quot;WB_1 priorityModeEVBattery 1&amp;quot;);;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem_set(&amp;quot;WB_1 priorityModeEVBattery 0&amp;quot;);;\&lt;br /&gt;
      }\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 7_WB_1_lp_1    : &amp;quot;.[$SELF:ui_command_4]};;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      fhem_set(&amp;quot;WB_1 Lademodus &amp;quot;.[$SELF:ui_command_4]);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 7_WB_1_lp_1    : Lademodus &amp;quot;.[$SELF:ui_command_4]};;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_4&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
8_Speicher_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                         ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [$SELF:ui_command_4]   eq &amp;quot;Hausspeicher_Sperren&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
      or [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot; and\&lt;br /&gt;
         [WB_1:lp_1_PlugStat]   eq &amp;quot;Plugged in&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_before_4&amp;quot;,[$SELF:ui_command_4]);;\&lt;br /&gt;
\&lt;br /&gt;
    if([$SELF:WR_1_Speicher_1_ExternControl_smart_laden_before] eq &amp;quot;---&amp;quot;) {\&lt;br /&gt;
\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        set_Reading(&amp;quot;WR_1_Speicher_1_ExternControl_smart_laden_before&amp;quot;,&amp;quot;aktiv&amp;quot;);;\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        set_Reading(&amp;quot;WR_1_Speicher_1_ExternControl_smart_laden_before&amp;quot;,&amp;quot;inaktiv&amp;quot;);;\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      fhem_set(&amp;quot;WR_1_Speicher_1_ExternControl cmd_2&amp;quot;);;\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 8_Speicher_sperren : smart_Laden startet&amp;quot;};;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_4&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                       ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
9_WB_1_Zaehler_Statistiken\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;) and                                     ## DOIF enabled\&lt;br /&gt;
     [00:01]\&lt;br /&gt;
   ) {\&lt;br /&gt;
    fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Day &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
    fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Day &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
\&lt;br /&gt;
    if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Month &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Month &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WB_1 lp_1_kWhCounter_init_Year &amp;quot;.[WB_1:lp_1_kWhCounter]);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WB_1 lp_2_kWhCounter_init_Year &amp;quot;.[WB_1:lp_2_kWhCounter]);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Kia_eNiro_PV DbLogExclude .*&lt;br /&gt;
attr Kia_eNiro_PV disable 0&lt;br /&gt;
attr Kia_eNiro_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Kia_eNiro_PV icon car&lt;br /&gt;
attr Kia_eNiro_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Kia_eNiro_PV sortby 401&lt;br /&gt;
attr Kia_eNiro_PV uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status_Laden {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $charge = (::ReadingsVal($car,&amp;quot;charging&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
   my $athome = (::ReadingsVal($car,&amp;quot;atHomeStanding&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
   my $chargeathome = ($charge &amp;amp;&amp;amp; $athome);;\&lt;br /&gt;
   my $connectedathome = ($athome &amp;amp;&amp;amp; ::ReadingsVal($car,&amp;quot;connected&amp;quot;,&amp;quot;false&amp;quot;) eq &amp;quot;true&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   my $ret = ($chargeathome ? &amp;quot;lädt zu Hause&amp;quot; : ($connectedathome ? &amp;quot;angeschlossen zu Hause&amp;quot; : ($athome ? &amp;quot;zu Hause&amp;quot; : ($charge ? &amp;quot;Lädt auswärts&amp;quot; : &amp;quot;unterwegs&amp;quot;))));;\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_tire {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $ret = &#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Reifendruck okay&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampAll&amp;quot;,&amp;quot;1&amp;quot;) != 0) {\&lt;br /&gt;
     my $VL = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampFL&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $HL = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampRL&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $VR = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampFR&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     my $HR = (::ReadingsVal($car,&amp;quot;status_tirePressureLamp_tirePressureLampRR&amp;quot;,&amp;quot;1&amp;quot;) eq &amp;quot;0&amp;quot;)?0:1;;\&lt;br /&gt;
     $ret = &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Reifen Störung&amp;lt;br&amp;gt;&#039;;;\&lt;br /&gt;
     if ($VL == 1){$ret.=&#039; /VL&#039;};;\&lt;br /&gt;
     if ($VR == 1){$ret.=&#039; /VR&#039;};;\&lt;br /&gt;
     if ($HL == 1){$ret.=&#039; /HL&#039;};;\&lt;br /&gt;
     if ($HR == 1){$ret.=&#039; /HR&#039;};;\&lt;br /&gt;
     $ret = $ret.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_door {\&lt;br /&gt;
   my($car)=@_;;\&lt;br /&gt;
   my $ret = &#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Türen okay&amp;lt;br&amp;gt;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_doorLock&amp;quot;,&amp;quot;false&amp;quot;) ne &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     my $VL = (::ReadingsVal($car,&amp;quot;status_doorOpen_frontLeft&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $HL = (::ReadingsVal($car,&amp;quot;status_doorOpen_backLeft&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $VR = (::ReadingsVal($car,&amp;quot;status_doorOpen_frontRight&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     my $HR = (::ReadingsVal($car,&amp;quot;status_doorOpen_backRight&amp;quot;,1) == 0)?0:1;;\&lt;br /&gt;
     $ret = &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Tür offen&amp;lt;br&amp;gt;&#039;;;\&lt;br /&gt;
     if ($VL == 1){$ret.=&#039; /VL&#039;};;\&lt;br /&gt;
     if ($VR == 1){$ret.=&#039; /VR&#039;};;\&lt;br /&gt;
     if ($HL == 1){$ret.=&#039; /HL&#039;};;\&lt;br /&gt;
     if ($HR == 1){$ret.=&#039; /HR&#039;};;\&lt;br /&gt;
     $ret = $ret.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_trunkOpen&amp;quot;,&amp;quot;true&amp;quot;) eq &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     $ret.=&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt; Kofferraum offen&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   if (::ReadingsVal($car,&amp;quot;status_hoodOpen&amp;quot;,&amp;quot;true&amp;quot;) eq &amp;quot;true&amp;quot;) {\&lt;br /&gt;
     $ret.=&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt; Motorhaube offen&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
   }\&lt;br /&gt;
   return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando &amp;quot;.::ReadingsTimestamp(&amp;quot;Kia_connect&amp;quot;,&amp;quot;status_time&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Auswahl / Kommunikation / Tacho / Info Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_getAll,car_lock,car_unlock&amp;quot;)|(([Kia_connect:req_active] eq &amp;quot;idle&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;idle&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;.[Kia_connect:req_active].&#039;&amp;lt;/span&amp;gt;&#039;) |::round([Kia_connect:odometer_value],0).&amp;quot; km&amp;quot;|FUNC_Status_Laden(&amp;quot;Kia_connect&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Accu&amp;lt;dd&amp;gt;Steuerung / Target Soc / Accu Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_3],&amp;quot;uzsuDropDown,---,setChargeTargetSoc,stopCharge,startCharge&amp;quot;)|&amp;quot;Target SOC&amp;quot;.widget([Kia_connect:status_evStatus_reservChargeInfos_targetSOClist_2_targetSOClevel_target],&amp;quot;selectnumbers,50,10,100,0,lin&amp;quot;).&amp;quot; %&amp;quot;|&amp;quot;&amp;quot;| FUNC_Status([Kia_connect:range],150,&amp;quot;red&amp;quot;,[Kia_connect:range],&amp;quot;orange&amp;quot;,[Kia_connect:range],250,&amp;quot;green&amp;quot;,[Kia_connect:range]).&amp;quot; km&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([Kia_connect:batSOC])).STY(::round([Kia_connect:batSOC],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Komfort&amp;lt;dd&amp;gt;Timer / Klima / Reifen / Türen / Accu Status 12V&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_timer_mode],&amp;quot;uzsuDropDown,Aus,heizen,kuehlen&amp;quot;).widget([$SELF:ui_timer_Start],&amp;quot;time&amp;quot;)|\&lt;br /&gt;
((::ReadingsVal(&amp;quot;Abfall_Abfuhr&amp;quot;,&amp;quot;Kiaheizen_days&amp;quot;,0) != 0)?&amp;quot;Klimatisierung&amp;lt;br&amp;gt;&amp;quot;.[Abfall_Abfuhr:Kiaheizen_connect_date].&amp;quot; &amp;quot;.[Abfall_Abfuhr:Kiaheizen_connect_time]:(([$SELF:ui_timer_mode] ne &amp;quot;Aus&amp;quot;)?&amp;quot;Klimatisierung&amp;lt;br&amp;gt;&amp;quot;.[$SELF:timer_04_c04]:&amp;quot;&amp;quot;))|FUNC_tire(&amp;quot;Kia_connect&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_door(&amp;quot;Kia_connect&amp;quot;)|\&lt;br /&gt;
&amp;quot;12 V&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([Kia_connect:bat12v])).STY(::round([Kia_connect:bat12v],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt; Auswahl / Temperatur / Klima Status / Temperatur innen&amp;lt;/dd&amp;gt;&amp;quot;| widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,stopClimate,startHeating,startCooling&amp;quot;)|\&lt;br /&gt;
&amp;quot;Heat&amp;quot;.widget([Kia_connect:status_airTemp_value_target_Winter],&amp;quot;selectnumbers,20,1,27,0,lin&amp;quot;).&amp;quot;°C&amp;lt;br&amp;gt;Cool&amp;quot;.widget([Kia_connect:status_airTemp_value_target_Sommer],&amp;quot;selectnumbers,16,1,25,0,lin&amp;quot;).&amp;quot;°C&amp;quot;|(([Kia_connect:status_airCtrlOn] eq &amp;quot;true&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Klima läuft&amp;lt;/span&amp;gt;&#039;:&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Klima aus&amp;lt;/span&amp;gt;&#039;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.(([Kia_connect:status_defrost] eq &amp;quot;true&amp;quot;)?&#039;Defrost ein&#039;:&#039;Defrost aus&#039;) |&amp;quot;Aktuell&amp;lt;br&amp;gt;&amp;quot;.[Kia_connect:status_airTemp_value].&amp;quot;°C&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;WallBox (WB_1_lp1)&amp;lt;dd&amp;gt;Lademodus / Info Status / Ladezeit / Leistung&amp;lt;/dd&amp;gt;&amp;quot;|[WB_1:ChargeMode].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_4],&amp;quot;uzsuDropDown,---,SofortLaden,Min+PV,NurPV,Stop,Standby,Vorrang_EV,Vorrang_Bat,Hausspeicher_Sperren&amp;quot;)|[WB_1:lp_1_PlugStat].&amp;quot; &amp;quot;.[WB_1:lp_1_ChargeStat]|[WB_1:lp_1_TimeRemaining]|[WB_1:lp_1_countPhasesInUse].&amp;quot;P &amp;quot;.[WB_1:lp_1_AConfigured].&amp;quot;A&amp;lt;br&amp;gt;&amp;quot;.[WB_1:lp_1_W].&amp;quot; W&amp;quot;&lt;br /&gt;
&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:24:24 ui_command_1 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-10 09:18:53 ui_command_2 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2021-11-09 07:56:54 ui_command_3 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:02:41 ui_command_4 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2022-01-12 13:02:41 ui_command_before_4 ---&lt;br /&gt;
setstate Kia_eNiro_PV 2021-11-29 09:56:58 ui_timer_Start 10:30&lt;br /&gt;
setstate Kia_eNiro_PV 2021-12-02 07:00:00 ui_timer_mode Aus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore mit Speicher=====&lt;br /&gt;
Zu diesem Thema gibt es noch die Wiki Seite [[Kostal Plenticore Plus]], die alles rund um den Wechselrichter und vieles mehr erklärt.&lt;br /&gt;
Die hier beschriebene openWB und Kia connect Anbindung bedient sich der Hausspeichersteuerung, um diesen beim Laden der BEV zu sperren.&lt;br /&gt;
Im DOIF kann an den entsprechenden Stellen natürlich auch ein anders Kommando zum Sperren verwendet werden.&lt;br /&gt;
&lt;br /&gt;
== Weiterführende Links ==&lt;br /&gt;
* [https://openwb.de openWB Website]&lt;br /&gt;
* [https://github.com/snaptec/openWB/wiki openWB Wiki bei GitHub]&lt;br /&gt;
* [https://www.openwb.de/forum/viewtopic.php?f=6&amp;amp;t=4159 openWB Forum (Diskussion zu diesem Artikel)]&lt;br /&gt;
* [https://openwb.de/forum/viewtopic.php?t=577 openWB Forum (Liste der MQTT-Topics)]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Elektromobilität]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39694</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39694"/>
		<updated>2024-11-17T11:31:32Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* MySQL Kommandos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.&#039;dwd_load&#039; TO &#039;fhemuser&#039;@&#039;%&#039;;             &amp;lt;&amp;lt;&amp;lt;&amp;lt; Das beschränkt auf nur eine Prozedure&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Es könnte auch gut sein einen extra root user anzulegen, um mit DbRep die MySQL Datenbank zu optimieren&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; GRANT ALL PRIVILEGES ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; WITH GRANT OPTION;&lt;br /&gt;
mysql&amp;gt; GRANT SHOW_ROUTINE ON *.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE, CREATE ROUTINE, ALTER ROUTINE ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT user,host FROM mysql.user;&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| user             | host           |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| fhemuser         | %              |&lt;br /&gt;
| fhemroot         | 192.168.178.57 |   &amp;lt;&amp;lt;&amp;lt; Das sollte man dann auf eine IP einschränken.&lt;br /&gt;
| root             | localhost      |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
&lt;br /&gt;
-- Hier kann man mal seine Proceduren auflisten&lt;br /&gt;
mysql&amp;gt; SHOW PROCEDURE STATUS WHERE Db = &#039;fhem&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wird mit folgenden Parametern aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39693</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39693"/>
		<updated>2024-11-17T11:28:11Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* MySQL Kommandos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.&#039;dwd_load&#039; TO &#039;fhemuser&#039;@&#039;%&#039;;             &amp;lt;&amp;lt;&amp;lt;&amp;lt; Das beschränkt auf nur eine Prozedure&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Es könnte auch gut sein einen extra root user anzulegen, um mit DbRep die MySQL Datenbank zu optimieren&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; GRANT ALL PRIVILEGES ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; WITH GRANT OPTION;&lt;br /&gt;
mysql&amp;gt; GRANT SHOW_ROUTINE ON *.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE, CREATE ROUTINE, ALTER ROUTINE ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT user,host FROM mysql.user;&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| user             | host           |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| fhemuser         | %              |&lt;br /&gt;
| fhemroot         | 192.168.178.57 |   &amp;lt;&amp;lt;&amp;lt; Das sollte man dann auf eine IP einschränken.&lt;br /&gt;
| root             | localhost      |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wird mit folgenden Parametern aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39692</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39692"/>
		<updated>2024-11-17T11:08:51Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* MySQL Kommandos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.&#039;dwd_load&#039; TO &#039;fhemuser&#039;@&#039;%&#039;;             &amp;lt;&amp;lt;&amp;lt;&amp;lt; Das beschränkt auf nur eine Prozedure&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Es könnte auch gut sein einen extra root user anzulegen, um mit DbRep die MySQL Datenbank zu optimieren&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; GRANT ALL PRIVILEGES ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; WITH GRANT OPTION;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT user,host FROM mysql.user;&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| user             | host           |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| fhemuser         | %              |&lt;br /&gt;
| fhemroot         | 192.168.178.57 |   &amp;lt;&amp;lt;&amp;lt; Das sollte man dann auf eine IP einschränken.&lt;br /&gt;
| root             | localhost      |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wird mit folgenden Parametern aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39691</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39691"/>
		<updated>2024-11-17T10:59:27Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* MySQL Kommandos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Es könnte auch gut sein einen extra root user anzulegen, um mit DbRep die MySQL Datenbank zu optimieren&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; IDENTIFIED WITH mysql_native_password BY &#039;&amp;lt;password&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; GRANT ALL PRIVILEGES ON `fhem`.* TO &#039;fhemroot&#039;@&#039;&amp;lt;IP Adresse&amp;gt;&#039; WITH GRANT OPTION;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT user,host FROM mysql.user;&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| user             | host           |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
| fhemuser         | %              |&lt;br /&gt;
| fhemroot         | 192.168.178.57 |   &amp;lt;&amp;lt;&amp;lt; Das sollte man dann auf eine IP einschränken.&lt;br /&gt;
| root             | localhost      |&lt;br /&gt;
+------------------+----------------+&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wird mit folgenden Parametern aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39146</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39146"/>
		<updated>2024-02-28T17:58:26Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wir mit folgenden Paramerter aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39145</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39145"/>
		<updated>2024-02-28T17:55:44Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
====KI Prognose Teil 3 - Python KI Prognose Skript====&lt;br /&gt;
Für die Verwendung der KI Prognose werden die folgenden Python Packages noch benötigt. Die Basis wäre hierbei der FHEM Docker Container.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Momentan habe ich das erstmal manuell im Container gemacht:&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install python3-pandas&lt;br /&gt;
    sudo apt-get install python3-pymysql&lt;br /&gt;
    sudo apt-get install python3-sqlalchemy&lt;br /&gt;
    sudo apt-get install python3-sklearn python3-sklearn-lib&lt;br /&gt;
    pip3 install fhem&lt;br /&gt;
&lt;br /&gt;
Für Docker sollte das im .yml File dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
    -e PIP_PKGS=&amp;quot;pandas pymysql sqlalchemy sklearn sklearn-lib&amp;quot;&lt;br /&gt;
    ob das mit dem &amp;quot;pip3 install fhem&amp;quot; so geht habe ich nicht getestet&lt;br /&gt;
&lt;br /&gt;
Die Python Skripte liegen bei mir im Ordner&lt;br /&gt;
&lt;br /&gt;
    ./python/bin&lt;br /&gt;
    [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/PV_KI_Prognose.py ./python/bin/PV_KI_Prognose.py]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das PV_KI_Prognose.py wir mit folgenden Paramerter aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
z.B. /opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Zum Test kann dies auch in &amp;quot;&amp;quot; in der FHEM Kommandozeile eingegeben werden, zuvor muss jedoch die MySQL Prozedur aufgerufen worden sein, damit die benötigte Tabelle mit den Daten erstellt worden ist.&lt;br /&gt;
2. Nach dem Testen kommt dieser Aufruf dann in das LogDBRep_PV_KI_Prognose Device und wird somit mit dem MySQL Prozeduraufruf synchronisiert.&lt;br /&gt;
   Bitte das LogDBRep_PV_KI_Prognose Device (Teil 1) aus dem vorherigen Absatz verwenden.&lt;br /&gt;
   Damit dann alles automatisch gestartet wird muss nun noch im WR_ctl Device ein Eintrag eingefügt werden.&lt;br /&gt;
3. Achtung, das WR_ctl Device beinhaltet jetzt die Forecast Daten und nicht wie früher das WR_1 Device.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Start der KI Prognose&lt;br /&gt;
## Der Reading Name und das Device werden in LogDBRep_PV_KI_Prognose im executeAfterProc eingestellt&lt;br /&gt;
##  &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.40 192.168.178.40 LogDBRep_PV_KI_Prognose WR_1_ctl Yield_fc&amp;quot;&lt;br /&gt;
##&lt;br /&gt;
2_KI_Prognose&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled&lt;br /&gt;
    and&lt;br /&gt;
      ReadingsVal(&amp;quot;LogDBRep_PV_KI_Prognose&amp;quot;,&amp;quot;PV_KI_Prognose&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;done&amp;quot;  ## Die Prognose darf nicht gerade laufen !!!&lt;br /&gt;
    and&lt;br /&gt;
  (&lt;br /&gt;
    ([05:00-22:00] and [:03]                                             ## In der PV-Zeit jede Stunde aktualisieren&lt;br /&gt;
    )&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_KI_Prognose&amp;quot;                           ## Hier wird das uiTable select ausgewertet&lt;br /&gt;
  )&lt;br /&gt;
   ) {&lt;br /&gt;
&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;LogDBRep_PV_KI_Prognose sqlCmd call dwd_load(curdate(),&#039;none&#039;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2_KI_Prognose : Start KI Prognose&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Netzwerkverbindung aus dem KI Python Skript werden die Zugansdaten im Filesystem abgelegt, damit sie nicht mit dem Skript ausversehen weiter gegeben werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ./python/pwd_fhem.json&lt;br /&gt;
    ./python/pwd_sql.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Verbindungsdaten werden in den Dateien wie folgt abgelegt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_[fhem|sql].json&lt;br /&gt;
{&amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Euer Username&amp;gt;&amp;quot;,&lt;br /&gt;
 &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Euer Passwort&amp;gt;&amp;quot;}&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FHEM und die Datenbank müssen nicht auf dem selben Rechner installiert werden. Die IP-Adressen werden dem Skript beim Aufruf mitgegeben.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht erforderlich die neuen readings mit DbLogInclude aus dem WR_1 Device in die Datenbank zu loggen, da dies bereits durch das PV_KI_Prognose Skript direkt geschieht, um einen passenden TIMESTAMP pro Stunde zu bekommen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn im LogDBRep_PV_KI_Prognose der verbose Level auf &amp;gt;= 3 steht kommen diverse Meldungen im Log:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
/usr/lib/python3/dist-packages/sklearn/externals/joblib.py:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module&#039;s documentation for alternative uses&lt;br /&gt;
  import imp&lt;br /&gt;
PV_KI_Prognose  running - start&lt;br /&gt;
PV_KI_Prognose  running - connected to 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - dwdfull read from DbLog 192.168.178.40&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loading&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor loaded&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor trained&lt;br /&gt;
PV_KI_Prognose  running - RandomForestRegressor fitted with yield&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc0_06  06 71&lt;br /&gt;
Yield_fc0_07  07 406&lt;br /&gt;
Yield_fc0_08  08 1629&lt;br /&gt;
Yield_fc0_09  09 3248&lt;br /&gt;
Yield_fc0_10  10 4664&lt;br /&gt;
Yield_fc0_11  11 6210&lt;br /&gt;
Yield_fc0_12  12 7078&lt;br /&gt;
Yield_fc0_13  13 5455&lt;br /&gt;
Yield_fc0_14  14 4034&lt;br /&gt;
Yield_fc0_15  15 1189&lt;br /&gt;
Yield_fc0_16  16 275&lt;br /&gt;
Yield_fc0_17  17 170&lt;br /&gt;
Yield_fc0_18  18 56&lt;br /&gt;
Yield_fc0_19  19 43&lt;br /&gt;
Yield_fc0_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7078 12:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               99&lt;br /&gt;
rest             99&lt;br /&gt;
morning          16228&lt;br /&gt;
afternoon        18300&lt;br /&gt;
day              34528&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  running - old forecast deleted&lt;br /&gt;
PV_KI_Prognose  running - start forecast&lt;br /&gt;
Yield_fc1_06  06 64&lt;br /&gt;
Yield_fc1_07  07 406&lt;br /&gt;
Yield_fc1_08  08 2103&lt;br /&gt;
Yield_fc1_09  09 4785&lt;br /&gt;
Yield_fc1_10  10 6902&lt;br /&gt;
Yield_fc1_11  11 7911&lt;br /&gt;
Yield_fc1_12  12 7078&lt;br /&gt;
Yield_fc1_13  13 5455&lt;br /&gt;
Yield_fc1_14  14 4034&lt;br /&gt;
Yield_fc1_15  15 1189&lt;br /&gt;
Yield_fc1_16  16 275&lt;br /&gt;
Yield_fc1_17  17 170&lt;br /&gt;
Yield_fc1_18  18 55&lt;br /&gt;
Yield_fc1_19  19 46&lt;br /&gt;
Yield_fc1_20  20 0&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
max       off/at 7911 11:00&lt;br /&gt;
Middayhigh_start 00:00&lt;br /&gt;
Middayhigh_stop  00:00&lt;br /&gt;
4h               101&lt;br /&gt;
rest             101&lt;br /&gt;
morning          22171&lt;br /&gt;
afternoon        18302&lt;br /&gt;
day              40473&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
PV_KI_Prognose  running - forecast written to FHEM&lt;br /&gt;
PV_KI_Prognose  done&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Wallboxen]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39084</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39084"/>
		<updated>2024-02-12T10:28:12Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Beispiel Diagramme */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39083</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39083"/>
		<updated>2024-02-12T10:27:31Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* =RAW Definition DWD_Forecast */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39079</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39079"/>
		<updated>2024-02-08T14:09:02Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39078</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39078"/>
		<updated>2024-02-08T14:08:22Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* RAW Definition Hauptverbraucher */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39077</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39077"/>
		<updated>2024-02-08T14:07:52Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Diagramme mit Grafana */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39076</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39076"/>
		<updated>2024-02-08T14:06:26Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* RAW Definition Hauptverbraucher */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39075</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39075"/>
		<updated>2024-02-08T14:03:31Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Energie Bilanz */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39074</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39074"/>
		<updated>2024-02-08T13:57:46Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
======DigitalOutputs schalten======&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2_API.txt Beispiel WR_2_API]&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die KI_Prognose() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion KI_Prognose() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
Die KI_Prognose Werte werden in dem WR_ctl Device abgelegt und sind dort als Yield_fc* zu finden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive       An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning      Aus    &amp;lt;&amp;lt;&amp;lt;&amp;lt; momentan keine Steuerung&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh       0      &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es gibt kein Mittags Hoch. Wird aus KI_Prognose() gesetzt &lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
             WR_ctl:Yield_fc0_middayhigh_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast in KI_Prognose() berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der WR_ctl:Yield_fc0_middayhigh_start wird dann unlimitiert bis zur WR_ctl:Yield_fc0_middayhigh_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_Speicher_1_ExternControl.txt Beispiel WR_1_Speicher_1_ExternControl]&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist auf Active_energy.* eingeschränkt, weshalb man seine zusätzlichen Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_0_KSEM.txt Beispiel WR_0_KSEM]&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
WR_ctl                                        DOIF                             Startet regelmäßige Aktionen zur zeitlichen Steuerung der PV-Anlage&lt;br /&gt;
                                                                               Dient der Anzeige von aktuellen und Statistischen Daten&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                        Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 05:00 bis 22:00&lt;br /&gt;
   2.1 KI_Prognose() für fc0 und fc1                                           Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 kurz nach Mitternacht&lt;br /&gt;
   3.1 4_WR_1_API_init_Werte                                                   Lesen und eventuell korrigieren der init Werte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC                    begrenzt dann morgens den MaxSOC&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday  und den MaxChargePowerAbs&lt;br /&gt;
        WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_ctl:Yield_fc0_middayhigh_start &amp;lt;&amp;gt; WR_ctl:Yield_fc0_middayhigh_stop  Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_ctl:Yield_fc0_middayhigh_stop                       Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von KI_Prognose() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-01-24 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== RAW Definition WR_ctl (DOIF)===&lt;br /&gt;
Das WR_ctl Device hat die zeitliche Steuerungder PV-Anlage übernommen und dient gleichzeitig der Anzeige von aktuellen und statistischen Werten im FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_ctl.txt Beispiel WR_ctl]&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_ctl Device mit uiTable angezeigt.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt. Mit DbRep Devicen kann man auch Vortag/Vormonat/Vorjahr im Wr_ctl direkt mitanzeigen lassen.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
ddefmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Month sqlCmd ckey:1)                      ## Bildet für verschiedene Devices die Monatsauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
\&lt;br /&gt;
## Tägliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Day sqlCmd ckey:1)                        ## Bildet für verschiedene Devices die Tagesauswertung\&lt;br /&gt;
\&lt;br /&gt;
## Quartal Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
(($md eq &amp;quot;01-01&amp;quot; or $md eq &amp;quot;04-01&amp;quot; or $md eq &amp;quot;07-01&amp;quot; or $md eq &amp;quot;10-01&amp;quot;) and [03:11])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Quarter sqlCmd ckey:1)                    ## Erstellt die Quartalsauswertung für WR_1\&lt;br /&gt;
\&lt;br /&gt;
## Jährliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
($md eq &amp;quot;01-01&amp;quot; and [08:05])\&lt;br /&gt;
 (set LogDBRep_Statistic_previous_Year sqlCmd ckey:1)                       ## Bildet für verschiedene Devices die Jahresauswertung&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2024.01.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast===&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_DWD_Forecast.txt Beispiel DWD_Forecast]&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_Astro.txt Beispiel Astro]&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/MySQL_dwd_load_Procedure.txt Beispiel dwd_load MySQL Procedure]&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose====&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/KI_Prognose/RAW_LogDBRep_PV_KI_Prognose.txt Beispiel LogDBRep_PV_KI_Prognose]&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&#039;&#039;&#039;Im JSON File sind noch weitere Kommentare enthalten, die bitte auch gelesen werden sollten.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Dashboard/Kostal-Flow_V2_JSON.txt Beispiel Grafana Dashboard]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/ Beispiele]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Hauptverbraucher_JSON.txt Beispiel Hauptverbraucher]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_KI_Prognose_JSON.txt Beispiel KI_Prognose]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Grafana/Diagramme/Diagramm_Leistungsbezug_JSON.txt Beispiel Leistungsbezug]&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF im Perl Modus) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/ Beispiel Wärmepumpe Novelan LAD9 mit vorgeschaltetem Stromzähler]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_PV_Perl.txt Beispiel LWP_PV_Perl PV Eigenverbrauch Steuerung]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_LWP_Counter.txt Beispiel LWP_Counter]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/W%c3%a4rmepumpe_Novelan_LAD9/RAW_shelly01.txt Beispiel Shelly PV Modus Umschaltung]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39072</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39072"/>
		<updated>2024-02-08T12:19:30Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
Die API Definition kann man sich mit folgendem Aufruf anschauen, sie wird von Kostal jedoch nicht supportet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erweiterung im WR_ctl, um die Zählerstände zu speichern&lt;br /&gt;
Im WR_ctl (DOIF im Perl Modus) gibt es einen Block für das Wiederherstellen der Zählerstände aus der DbLog, sofern das Monitoring bereits einen Jahres Zyklus gelaufen ist. Der Block 4_WR_1_API_init_Werte kann über das uiTable Pull Down Menü im WR_ctl im Bereich &amp;quot;WR_1_API Kommando Auswahl&amp;quot; auch manuell ausgeführt werden, was nach einem FHEM Absturz eventuell notwendig sein könnte. Die Notwendigkeit erkennt man an negativen Werten in der Spalte &amp;quot;aktuell&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====DigitalOutputs schalten=====&lt;br /&gt;
Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_2_API DbLogExclude .*&lt;br /&gt;
attr WR_2_API DbLogInclude Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API authRetries 1&lt;br /&gt;
attr WR_2_API comment Version 2021.04.27 16:00\&lt;br /&gt;
Passworte für die Abfrage des WR_2_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_2_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_2_API disable 0&lt;br /&gt;
attr WR_2_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_2_API enableControlSet 0&lt;br /&gt;
attr WR_2_API enableCookies 1&lt;br /&gt;
attr WR_2_API event-on-update-reading auth_.*,Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API get01Data %START%&lt;br /&gt;
attr WR_2_API get01Name 01_auth_start&lt;br /&gt;
attr WR_2_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API get02Data %FINISH%&lt;br /&gt;
attr WR_2_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_2_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API get03Data %SESSION%&lt;br /&gt;
attr WR_2_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_2_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_2_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_2_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_2_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_2_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_2_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_2_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get04JSON .&lt;br /&gt;
attr WR_2_API get04Name 04_auth_me&lt;br /&gt;
attr WR_2_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_2_API get05-1Name info_api_version&lt;br /&gt;
attr WR_2_API get05-2Name info_hostname&lt;br /&gt;
attr WR_2_API get05-3Name info_name&lt;br /&gt;
attr WR_2_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_2_API get05JSON .&lt;br /&gt;
attr WR_2_API get05Name 05_info_version&lt;br /&gt;
attr WR_2_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_2_API get20-10Format %.2f&lt;br /&gt;
attr WR_2_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-11Format %.2f&lt;br /&gt;
attr WR_2_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-12Format %.2f&lt;br /&gt;
attr WR_2_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-13Format %.2f&lt;br /&gt;
attr WR_2_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_2_API get20-14Format %.2f&lt;br /&gt;
attr WR_2_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_2_API get20-15Format %.2f&lt;br /&gt;
attr WR_2_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_2_API get20-16Format %.2f&lt;br /&gt;
attr WR_2_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_2_API get20-17Format %.2f&lt;br /&gt;
attr WR_2_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_2_API get20-18Format %.2f&lt;br /&gt;
attr WR_2_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_2_API get20-19Format %.2f&lt;br /&gt;
attr WR_2_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_2_API get20-1Format %.2f&lt;br /&gt;
attr WR_2_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_2_API get20-20Format %.2f&lt;br /&gt;
attr WR_2_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_2_API get20-21Format %.2f&lt;br /&gt;
attr WR_2_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_2_API get20-22Format %.2f&lt;br /&gt;
attr WR_2_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_2_API get20-23Format %.2f&lt;br /&gt;
attr WR_2_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_2_API get20-24Format %.2f&lt;br /&gt;
attr WR_2_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_2_API get20-25Format %.2f&lt;br /&gt;
attr WR_2_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_2_API get20-26Format %.2f&lt;br /&gt;
attr WR_2_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-27Format %.2f&lt;br /&gt;
attr WR_2_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-28Format %.2f&lt;br /&gt;
attr WR_2_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-29Format %.2f&lt;br /&gt;
attr WR_2_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_2_API get20-2Format %.2f&lt;br /&gt;
attr WR_2_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_2_API get20-30Format %.2f&lt;br /&gt;
attr WR_2_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_2_API get20-31Format %.2f&lt;br /&gt;
attr WR_2_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_2_API get20-32Format %.2f&lt;br /&gt;
attr WR_2_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_2_API get20-33Format %.2f&lt;br /&gt;
attr WR_2_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_2_API get20-34Format %.2f&lt;br /&gt;
attr WR_2_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_2_API get20-35Format %.2f&lt;br /&gt;
attr WR_2_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_2_API get20-36Format %.2f&lt;br /&gt;
attr WR_2_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_2_API get20-37Format %.2f&lt;br /&gt;
attr WR_2_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_2_API get20-38Format %.2f&lt;br /&gt;
attr WR_2_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_2_API get20-39Format %.2f&lt;br /&gt;
attr WR_2_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_2_API get20-3Format %.2f&lt;br /&gt;
attr WR_2_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_2_API get20-40Format %.2f&lt;br /&gt;
attr WR_2_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_2_API get20-41Format %.2f&lt;br /&gt;
attr WR_2_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_2_API get20-42Format %.2f&lt;br /&gt;
attr WR_2_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_2_API get20-43Format %.2f&lt;br /&gt;
attr WR_2_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_2_API get20-44Format %.2f&lt;br /&gt;
attr WR_2_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_2_API get20-45Format %.2f&lt;br /&gt;
attr WR_2_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_2_API get20-46Format %.2f&lt;br /&gt;
attr WR_2_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_2_API get20-47Format %.2f&lt;br /&gt;
attr WR_2_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_2_API get20-48Format %.2f&lt;br /&gt;
attr WR_2_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_2_API get20-49Format %.2f&lt;br /&gt;
attr WR_2_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_2_API get20-4Format %.2f&lt;br /&gt;
attr WR_2_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_2_API get20-50Format %.2f&lt;br /&gt;
attr WR_2_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_2_API get20-51Format %.2f&lt;br /&gt;
attr WR_2_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_2_API get20-52Format %.2f&lt;br /&gt;
attr WR_2_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_2_API get20-53Format %.2f&lt;br /&gt;
attr WR_2_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_2_API get20-54Format %.2f&lt;br /&gt;
attr WR_2_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_2_API get20-55Format %.2f&lt;br /&gt;
attr WR_2_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_2_API get20-56Format %.2f&lt;br /&gt;
attr WR_2_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_2_API get20-57Format %.2f&lt;br /&gt;
attr WR_2_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_2_API get20-58Format %.2f&lt;br /&gt;
attr WR_2_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_2_API get20-59Format %.2f&lt;br /&gt;
attr WR_2_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_2_API get20-5Format %.2f&lt;br /&gt;
attr WR_2_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_2_API get20-60Format %.2f&lt;br /&gt;
attr WR_2_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_2_API get20-61Format %.2f&lt;br /&gt;
attr WR_2_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_2_API get20-62Format %.2f&lt;br /&gt;
attr WR_2_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_2_API get20-63Format %.2f&lt;br /&gt;
attr WR_2_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_2_API get20-64Format %.2f&lt;br /&gt;
attr WR_2_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_2_API get20-65Format %.2f&lt;br /&gt;
attr WR_2_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_2_API get20-6Format %.2f&lt;br /&gt;
attr WR_2_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_2_API get20-7Format %.2f&lt;br /&gt;
attr WR_2_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_2_API get20-8Format %.2f&lt;br /&gt;
attr WR_2_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_2_API get20-9Format %.2f&lt;br /&gt;
attr WR_2_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_2_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_2_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_2_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_2_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get40Name 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable&lt;br /&gt;
attr WR_2_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_2_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_2_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_2_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get60Name 60_update_status&lt;br /&gt;
attr WR_2_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_2_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_2_API icon sani_solar&lt;br /&gt;
attr WR_2_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_2_API reading0101JSON nonce&lt;br /&gt;
attr WR_2_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_2_API reading0102JSON rounds&lt;br /&gt;
attr WR_2_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_2_API reading0103JSON salt&lt;br /&gt;
attr WR_2_API reading0103Name auth_salt&lt;br /&gt;
attr WR_2_API reading0104JSON transactionId&lt;br /&gt;
attr WR_2_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_2_API reading0201JSON signature&lt;br /&gt;
attr WR_2_API reading0201Name auth_signature&lt;br /&gt;
attr WR_2_API reading0202JSON token&lt;br /&gt;
attr WR_2_API reading0202Name auth_token&lt;br /&gt;
attr WR_2_API reading0301JSON message&lt;br /&gt;
attr WR_2_API reading0301Name info_message&lt;br /&gt;
attr WR_2_API reading0302JSON error&lt;br /&gt;
attr WR_2_API reading0302Name info_error&lt;br /&gt;
attr WR_2_API reading03JSON sessionId&lt;br /&gt;
attr WR_2_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_2_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_2_API replacement01Mode expression&lt;br /&gt;
attr WR_2_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_2_API replacement01Value {ReadingsVal(&amp;quot;WR_2_config&amp;quot;,&amp;quot;IP-WR_2&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement02Mode expression&lt;br /&gt;
attr WR_2_API replacement02Regex %START%&lt;br /&gt;
attr WR_2_API replacement02Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement04Mode expression&lt;br /&gt;
attr WR_2_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_2_API replacement04Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement05Mode expression&lt;br /&gt;
attr WR_2_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_2_API replacement05Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement06Mode reading&lt;br /&gt;
attr WR_2_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_2_API replacement06Value auth_signature&lt;br /&gt;
attr WR_2_API replacement07Mode reading&lt;br /&gt;
attr WR_2_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_2_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_2_API replacement08Mode expression&lt;br /&gt;
attr WR_2_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_2_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API replacement09Mode expression&lt;br /&gt;
attr WR_2_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_2_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set06Method POST&lt;br /&gt;
attr WR_2_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_2_API set06NoArg 1&lt;br /&gt;
attr WR_2_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_2_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_2_API set4002FollowGet 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_2_API set4002Method PUT&lt;br /&gt;
attr WR_2_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_2_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_2_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_2_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_2_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_2_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_2_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_2_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_2_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_2_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_2_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_2_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_2_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_2_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_2_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_2_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_2_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_2_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_2_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_2_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_2_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_2_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_2_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_2_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_2_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_2_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_2_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_2_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_2_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_2_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_2_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_2_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_2_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_2_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_2_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_2_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_2_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_2_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_2_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_2_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_2_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_2_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_2_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_2_API set50JSON .&lt;br /&gt;
attr WR_2_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_2_API set50ParseResponse 1&lt;br /&gt;
attr WR_2_API set50TextArg 1&lt;br /&gt;
attr WR_2_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_2_API showBody 1&lt;br /&gt;
attr WR_2_API showError 1&lt;br /&gt;
attr WR_2_API sid01Data %START%&lt;br /&gt;
attr WR_2_API sid01ParseResponse 1&lt;br /&gt;
attr WR_2_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API sid02Data %FINISH%&lt;br /&gt;
attr WR_2_API sid02ParseResponse 1&lt;br /&gt;
attr WR_2_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API sid03Data %SESSION%&lt;br /&gt;
attr WR_2_API sid03ParseResponse 1&lt;br /&gt;
attr WR_2_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API sortby 212&lt;br /&gt;
attr WR_2_API timeout 7&lt;br /&gt;
attr WR_2_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion Solar_forecast() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive        An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning       Aus = momentan keine Steuerung&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0          0 = Es gibt kein Mittags Hoch. Wird aus Solar_forecast() gesetzt &lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der PV_1:Solar_middayhigh_fc0_start wird dann unlimitiert bis zur PV_1:Solar_middayhigh_fc0_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_ExternControl DOIF ################################################################################################################\&lt;br /&gt;
## 1 Speicher Status vom WR_1_Speicher_1 aktualisieren.\&lt;br /&gt;
##   Dies geschieht über das WR_1_API Device, da der Speicher direkt am Wechselrichter angeschlossen ist.\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_WR_1_Speicher_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [:52]                                                           ## jede Stunde\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 21_Battery_Information&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 22_Battery_InternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 23_Battery_ExternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_1  : Speicher Status abfrage&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Wenn die Ladung im Herbst/Winter unter MinSoc geht allen PV Überschuss in die Batterie laden\&lt;br /&gt;
##\&lt;br /&gt;
## Im Winter kann der MinSoc, durch den WR Eigenverbrauch, unterschritten werden, deshalb wird vorher auf\&lt;br /&gt;
## smarte_laden umgeschaltet, bis die Batterie wieder einen hohen Soc erreicht hat. Siehe cmd_3 laden_beendet\&lt;br /&gt;
##\&lt;br /&gt;
2_smart_Laden_start_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [WR_ctl:Yield_fc0_day] &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit]     ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
       and [WR_1:Act_state_of_charge] &amp;lt;= [WR_1_API:Battery_InternControl_MinSoc]  ## Achtung der Speicherstand wird zu niedrig\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100             ## Der Speicher steht auf Entladen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.1: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.1: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_smart_Laden_start_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [WB_1:lp_1_ChargeStat]      eq &amp;quot;loading&amp;quot;                        ## Ein Fahrzeug wird gerade geladen\&lt;br /&gt;
     and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;Aus&amp;quot;                            ## Der Speicher darf nicht zum Laden verwendet werden\&lt;br /&gt;
     or\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot;                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot; ) {\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before aktiv&amp;quot;);;                ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before inaktiv&amp;quot;);;              ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
    } else {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_2.2: WallBox es wird gerade geladen&amp;quot;};;       ## Der vorherige Zustand war schon bekannt\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.2: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.2: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Beim erreichen von 90% Soc die Entladung wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:SpeicherEntladung] eq &amp;quot;Automatik&amp;quot;                            ## Nur für den Automatik Modus\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100         ## Das Speicher Entladen ist geperrt\&lt;br /&gt;
       and\&lt;br /&gt;
       [WR_1:Act_state_of_charge] &amp;gt;= 80                                  ## Der Speicher ist bereits 80% voll\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell aktiviert\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.1: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.1: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_smart_Laden_beenden_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;inaktiv&amp;quot;                      ## Vorher war es nicht aktiv\&lt;br /&gt;
      )\&lt;br /&gt;
     or  [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;                             ## Der Speicher darf zum Laden verwendet werden\&lt;br /&gt;
     or  [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                       ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.2: Batterie wird mit &amp;quot;.[?$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.2: Batterie auf &amp;quot;.[?WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (    [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;\&lt;br /&gt;
        and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;) {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF cmd_3.2: MaxSOC Limitierung wegen Wallboxnutzung abgeschaltet&amp;quot;;;}\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Wenn vor dem WB_1 laden das smart_Laden aktiv gewesen ist geht es zurück in den Zustand\&lt;br /&gt;
## \&lt;br /&gt;
3_smart_Laden_umschalten_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;aktiv&amp;quot;                        ## Vorher war es nicht aktiv\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_umschalten_WB_1&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                        ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: WB_1 laden beendet, reaktivieren des smart_Laden&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.3: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.3: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Bei Zeitsteuerung und guter Prognose bei 40% wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Zeit\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [$SELF:SpeicherEntladung]  eq &amp;quot;Zeit&amp;quot;                            ## Nur für den Zeit Modus\&lt;br /&gt;
     and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]            ## Zeitfenster aktiv ist\&lt;br /&gt;
     and [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                        ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (\&lt;br /&gt;
            [WR_1:Act_state_of_charge] &amp;gt;= 40                             ## und einem Stand von Soc 40%\&lt;br /&gt;
        and\&lt;br /&gt;
            ([WR_ctl:Yield_fc0_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit]   ## wenn es heute oder \&lt;br /&gt;
          or [WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit])  ## morgen viel Leistung gibt\&lt;br /&gt;
       )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_zeit&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, SpeicherExternTrigger, freigegeben&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Die Leistungsprognose von &amp;quot;.[$SELF:SpeicherMinSOC_fc1_Limit].&amp;quot; wird überschritten&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;frei&amp;quot;);;                         ## Trigger freigeben\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                           ## Signalisiere entladen im stateFormat\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);; ## Speicher für Entladung freigeben\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Freigabe der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. ([07:00-16:00]\&lt;br /&gt;
4_Trigger\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]       ## Zeitfenster aktiv ist\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot;                               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot; ) {                             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;  ## Speicher für Entladung freigeben\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                            ## Signalisiere entladen im stateFormat\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_4  : SpeicherExternTrigger, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Sperren der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. [16:00-07:00]\&lt;br /&gt;
5_Trigger_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitEnde]-[$SELF:SpeicherZeitStart]]       ## Zeitfenster verlassen wurde\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger_sperren&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;## Speicher für Entladung sperren\&lt;br /&gt;
  set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                             ## Signalisiere gesperrt im stateFormat\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
    {Log 3, &amp;quot;$SELF cmd_5  : SpeicherExternTrigger, Entlademodus gesperrt (Tarif oder Trigger)&amp;quot;};;\&lt;br /&gt;
 }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
6_Kommando_Wiederholung\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [WR_1_API:Battery_Control] &amp;gt; 0 and                                ## Wenn die ExternControl am WR konfiguriert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatActive]  eq &amp;quot;An&amp;quot; and                      ## Wenn die ExternControl Aktiviert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatRunning] eq &amp;quot;An&amp;quot; and                      ## Wenn es  ExternControl Kommandos zum Senden gibt\&lt;br /&gt;
       [  {sunrise_abs(&amp;quot;HORIZON=+5.0&amp;quot;,0,&amp;quot;6:00&amp;quot;,&amp;quot;08:35&amp;quot;)}                 ## Innerhalb der Photovoltaik Zeit\&lt;br /&gt;
        - {sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)} ] and\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot; ) {              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   my $MaxChargePowerTime = 0;;\&lt;br /&gt;
   my $MaxChargePowerAbs_midday = 0;;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {                              ## Hier können noch Testmeldungen hin\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : SpeicherMiddayControlRunning &amp;quot;.[$SELF:SpeicherMiddayControlRunning];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_start   &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_stop    &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop];;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlRunning] eq &amp;quot;An&amp;quot; ) {                  ## Wurde ein Mittagshoch ermittelt und aktiviert?\&lt;br /&gt;
\&lt;br /&gt;
     if ( [WR_1:Act_state_of_charge] &amp;gt;= [WR_1_API:Battery_InternControl_MinSoc] *3 ) {\&lt;br /&gt;
       if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs 0&amp;quot;);;     ## nicht vor z.B. 09:00 Uhr starten. Ladung auf 0 Watt setzen\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                                              ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot; Uhr noch nicht laden&amp;quot;;;\&lt;br /&gt;
         }\&lt;br /&gt;
       } else {                                                          ## Ist noch Vormittag?\&lt;br /&gt;
         if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
           ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning]);;\&lt;br /&gt;
           set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMidday_MaxSOC].&#039;)&#039;);;\&lt;br /&gt;
           if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                       ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; limitieren&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning].&amp;quot; limitiert&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSOC auf &amp;quot;.[$SELF:SpeicherMidday_MaxSOC].&amp;quot; % limitiert&amp;quot;;;\&lt;br /&gt;
           }\&lt;br /&gt;
         }\&lt;br /&gt;
       }\&lt;br /&gt;
     } else {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_6  : Battery_InternControl_MinSoc auf &amp;quot;.([WR_1_API:Battery_InternControl_MinSoc] *3).&amp;quot; % laden&amp;quot;;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
     if (::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) &amp;lt;= time and  ## Es ist Mittag\&lt;br /&gt;
         time &amp;lt;= ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
\&lt;br /&gt;
       my $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;)+3600 ));;\&lt;br /&gt;
          $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ));;\&lt;br /&gt;
\&lt;br /&gt;
       if ([$SELF:SpeicherMaxSOCControlRunning] eq &amp;quot;An&amp;quot; and                     ## Somit bleibt weniger Platz im Speicher und es ist\&lt;br /&gt;
           time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.$wait.&amp;quot;:00&amp;quot;) ) {  ## besser nicht zu früh beginnen.\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden wegen MaxSoc von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; auf &amp;quot;.$wait.&amp;quot; Uhr verschoben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
       } else {                                                                 ## auch jetzt nicht mit voller Leistung laden\&lt;br /&gt;
\&lt;br /&gt;
         if ([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0) {            ## dynamische Leistungsermittlung oder vorgewählter Wert\&lt;br /&gt;
           $MaxChargePowerTime       = ::round((::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) - time) / 3600 , 2);;  ## Mittags Ladezeit bestimmen\&lt;br /&gt;
\&lt;br /&gt;
           my $MaxChargePowerLimit   = (1 - ::round($MaxChargePowerTime,2) * [$SELF:SpeicherMidday_MaxChargePowerSteigung]);;  ## Zu Beginn etwas langsamer anfangen, empirisch ermittelt\&lt;br /&gt;
\&lt;br /&gt;
           $MaxChargePowerAbs_midday = ::round( [WR_1:Battery_work_capacity] * ([$SELF:SpeicherMaxSOC_Actual] - [WR_1:Act_state_of_charge]) / 100 * $MaxChargePowerLimit, 0);;\&lt;br /&gt;
\&lt;br /&gt;
           if ($MaxChargePowerAbs_midday &amp;lt; 500) { $MaxChargePowerAbs_midday = 500 };;## Nicht unter 1000\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Mittags $MaxChargePowerTime h mit $MaxChargePowerAbs_midday W laden&amp;quot;;;\&lt;br /&gt;
         } else {\&lt;br /&gt;
           $MaxChargePowerAbs_midday = [$SELF:SpeicherMidday_MaxChargePowerAbs_midday];; ## Nimm den vorgewählten Wert\&lt;br /&gt;
         };;\&lt;br /&gt;
\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs $MaxChargePowerAbs_midday&amp;quot;);;\&lt;br /&gt;
         set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMaxSOC_Actual].&#039;)&#039;);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; bis &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; freigegeben&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf $MaxChargePowerAbs_midday limitiert&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;\&lt;br /&gt;
         };;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
\&lt;br /&gt;
     if (time &amp;gt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {    ## Es ist Nachmittag und die\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                                         ## Mittagssteuerung wird abgeschaltet\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl nach &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; beendet&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;An&amp;quot; and ## Nur MaxSOC soll begrenzt werden\&lt;br /&gt;
       [$SELF:SpeicherMaxSOC_Actual] &amp;lt;= 100                        and                                          \&lt;br /&gt;
       ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;Aus&amp;quot;) { ##  sobald die Mittagssteuerung fertig ist\&lt;br /&gt;
     if ([WR_1:SW_Home_own_consumption_from_Battery] &amp;gt; 500) {             ## Sollte der Speicher bereits jetzt verwendet werden ist es besser\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                 ## die MaxSOC Begrenzung zu stoppen\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMaxSOCControl wegen Speicher Nutzung am Nachmittag beendet&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_6  : ExternControl Kommando Wiederholung erledigt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Bestimmung eines möglichen SOC für den nächsten Morgen und\&lt;br /&gt;
##   Vorbereitung für ein Leistungshoch am Mittag\&lt;br /&gt;
##\&lt;br /&gt;
7_SOC_Calculation\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       ([WR_1_API:Battery_Control] &amp;gt; 0 and                               ## Ist die ExternControl am WR aktiviert\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot;   or                ## Ist MaxSOC Limit konfiguriert\&lt;br /&gt;
         [$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; ) and               ## Ist Midday Kontrolle konfiguriert\&lt;br /&gt;
        [$SELF:SpeicherMaxSOC_MinSOC_Time]  eq &amp;quot;NULL&amp;quot; and                ## Wurde ein minimum SOC bereits ermittelt\&lt;br /&gt;
        [{sunrise_abs(&amp;quot;HORIZON=+4.0&amp;quot;,0,&amp;quot;5:50&amp;quot;,&amp;quot;08:35&amp;quot;)} - 10:00 ] and\&lt;br /&gt;
        [WR_1:SW_Home_own_consumption_from_PV] == [WR_1:SW_Home_own_consumption] ## Die PV Leistung reicht für&#039;s Haus\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot; ) {                     ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   my $MinSOC_Time   = &amp;quot;gefunden&amp;quot;;;                                       ## Nur einmal am Tag bearbeiten\&lt;br /&gt;
   my $MinSOC_MinSOC = ::round([WR_1:Act_state_of_charge],0);;            ## Festgestellter MinSOC am Morgen          Magic ???\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,$MinSOC_Time);;\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,$MinSOC_MinSOC);;\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                               ## merken und melden\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_MinSOC_Time &amp;quot;.$MinSOC_Time.&amp;quot; &amp;quot;.$MinSOC_MinSOC.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot; and\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt; 100 and     ## Der Speicher darf nicht im smart_laden sein\&lt;br /&gt;
       [Pool_Counter:countsPerDay] == 0 and                              ## Achtung der Pool und auch die LWP\&lt;br /&gt;
       [LWP_Counter:countsPerDay]  == 0 ) {                              ##    sollten nicht mehr früh morgens laufen\&lt;br /&gt;
\&lt;br /&gt;
     my $SpeicherSOCMinimum = [WR_1_API:Battery_InternControl_MinSoc]*3;; ## 3x MinSOC als reserve vorsehen\&lt;br /&gt;
     my $SpeicherSOCDayBefore = ::round(ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;, 100),0);; ## wie voll war er gestern noch?\&lt;br /&gt;
     my $SpeicherSOCNew       = 0;;\&lt;br /&gt;
     my $SpeicherSOCDelta     = 0;;\&lt;br /&gt;
\&lt;br /&gt;
     if ([WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMaxSOC_fc1_Limit] and\&lt;br /&gt;
         $MinSOC_MinSOC                   &amp;gt; $SpeicherSOCMinimum ) {      ## Ist der Speicher voller als er müsste?\&lt;br /&gt;
\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Leistung Prognose &amp;quot;.[WR_ctl:Yield_fc1_day].&amp;quot; wh &amp;gt; Schwellwert &amp;quot;.[$SELF:SpeicherMaxSOC_fc1_Limit].&amp;quot; wh&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Speicherladung aktuell $MinSOC_MinSOC % &amp;gt; Minimum $SpeicherSOCMinimum %&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
       $SpeicherSOCDelta = $MinSOC_MinSOC - $SpeicherSOCMinimum;;         ## Was wäre noch übrig?\&lt;br /&gt;
       if ($SpeicherSOCDelta &amp;lt;= 10) {                                    ## Das lohnt sich nicht\&lt;br /&gt;
         $SpeicherSOCNew = $SpeicherSOCDayBefore;;                        ## den Wert von gestern einfach beibehalten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCDayBefore);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; % gesichert&amp;quot;};;\&lt;br /&gt;
       } else {\&lt;br /&gt;
         $SpeicherSOCNew = ::round(($SpeicherSOCDayBefore+$SpeicherSOCDayBefore-$SpeicherSOCDelta)/2 ,0);;  ## um den Durchschnitt verringern\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCNew);;           ## Das soll heute in den Speicher\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCNew.&amp;quot; % neu berechnet und gesichert&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
       if ($SpeicherSOCNew &amp;gt; 0) {                                        ## Es gibt einen neuen MaxSoc\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;               ## Senden starten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Wiederholung starten\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual &amp;quot;.$SpeicherSOCNew.&amp;quot; % geplant&amp;quot;};;\&lt;br /&gt;
       } else {                                                          ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
     } else {                                                            ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
       if ($MinSOC_MinSOC  &amp;lt; $SpeicherSOCMinimum ) {                     ## MaxSoc leicht erhöhen, da er etwas zu niedrig war\&lt;br /&gt;
         $SpeicherSOCNew   = ::round($SpeicherSOCDayBefore+$SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         $SpeicherSOCDelta = ::round($SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,$SpeicherSOCNew);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore wurde um &amp;quot;.$SpeicherSOCDelta.&amp;quot; erhöht&amp;quot;};;\&lt;br /&gt;
       }\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt, da die Prognose für morgen zu schlecht ist&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; and                   ## Soll für mittags noch Platz gehalten werden?\&lt;br /&gt;
       [WR_ctl:Yield_fc0_middayhigh] == 1 ) {                                                    \&lt;br /&gt;
																	                           \&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Die Mittagskontrolle aktivieren\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){                              ## (die Uhrzeiten wurden bereits durch Solar_forecast() im WR_1 Device eingetragen)\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie SpeicherMiddayControlRunning vorbereitet&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_start &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_start&amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_stop  &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_stop &amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {                                                              ## Kein Mittagshoch\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMiddayControl es wird kein Middayhigh geben&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Reset der ExternControl Kommandos\&lt;br /&gt;
##\&lt;br /&gt;
8_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;16:00&amp;quot;,&amp;quot;21:00&amp;quot;)}]                ## hier sollte das Ende der PV-Zeit sein\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot;                                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot; ) {                               ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
																			                   \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Max SOC Steuerung zurücksetzen\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                           ## SpeicherMaxSOC_Actual auf Default\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,[WR_1:Act_state_of_charge]);;   ## Den vor Tages Wert merken\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,&amp;quot;NULL&amp;quot;);;                     ## Die MinSOC Time löschen\&lt;br /&gt;
																						       \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Midday Steuerung zurücksetzen\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_8  : ExternControl zurückgesetzt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird, das ist dann im Herbst/Winter\&lt;br /&gt;
##\&lt;br /&gt;
9_MinSOC_Winter\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit] and        ## Wenn morgen das Minimum an Leistung nicht erreicht wird\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;lt; [$SELF:SpeicherMinSOC_Winter]    and        ## und der MinSoc unter der Winter Wert eingestellt ist\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot; or\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;NULL&amp;quot; and [10:01])\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Winter]);;        ## Den MinSOC anheben, um eine eventuelle\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : Batterie MinSoc auf Winterbetrieb&amp;quot;};;        ## Notladung zu verhindern\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Im Winter Betrieb keine MaxSOC Begrenzung\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## und keine Midday Steuerung\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : MaxSOC Begrenzung und Midday Steuerung im Winterbetrieb deaktiviert&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Umschaltung des MinSoc wenn viel Leistung erwartet wir, das wäre dann Frühling/Sommer\&lt;br /&gt;
##\&lt;br /&gt;
10_MinSOC_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit] and         ## sobald viel Ladung erwartet wird und der MinSoc noch\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;gt; [$SELF:SpeicherMinSOC_Sommer]    and         ## noch im Winter Modus ist\&lt;br /&gt;
        [10:09] \&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
                                                                                           \&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Sommer]);;        ## den MinSOC auf Sommerbetrieb herabsetzen, es kann\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_10 : Batterie MinSoc auf Sommerbetrieb&amp;quot;};;                              ## wieder mehr Leistung genutzt werden\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Der Speicher ist voll geladen. Hier wird das ständige nachladen auf 100 % vermieden.\&lt;br /&gt;
##\&lt;br /&gt;
11_Speicher_voll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ( [WR_ctl:Yield_fc0_day]        &amp;gt;  [$SELF:SpeicherMaxSOC_fc1_Limit] and    ## 1) sobald viel Leistung erwartet wird und der Speicher voll ist\&lt;br /&gt;
         [WR_1:Act_state_of_charge]    == 100                              and    ##    den MaxSOC wieder reduzieren, damit nicht immer nachgeladen wird\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_Actual] ne 95                                      ##   \&lt;br /&gt;
        or\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_Actual] == 95 and                                  ## 2) oder das Nachladen gestoppt wurde\&lt;br /&gt;
         [WR_1:Act_state_of_charge] &amp;lt;=  98  and                                   ##    und der SOC unte 98 % gefallen ist\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,-7200,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)}])                    ##    zwei Stunden vor Sonnenuntergang eventuell wieder nachladen\&lt;br /&gt;
       ) and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot; ) {                       ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([WR_1:Act_state_of_charge] &amp;lt;= 98) {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                         ## Eventuell noch mal nachladen\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 100 % nachladen&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;95&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                       ## Start regelmäßiges senden der Kommandos\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## MaxSOC Begrenzung weil Speicher bereits 100 % hat\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 95 % reduziert&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 WR_1_Speicher_1 DC_Power_Abs setzen z.B. zur Zwangsentladung\&lt;br /&gt;
##     dies muss manuell wiederholt werden. Danach hängt es vom WR ab, wie er die Speichersteuerung fortsetzt.\&lt;br /&gt;
12_DC_Power_Abs \&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot;                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot; ) {                        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs &amp;quot;.[$SELF:SpeicherDcPowerAbs]);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_12 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 13 WR_1_Speicher_1 Status aktualisieren.\&lt;br /&gt;
##   Dies ist momentan nur für den BYD HV Speicher, da der BYD HVS eine direkte Abfrage nicht unterstützt.\&lt;br /&gt;
##   Wer keinen BYD HV Speicher hat kann das löschen\&lt;br /&gt;
13_Status_WR_1_Speicher_1_BYD\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
      or\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot; ) {          ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 BatteryInformation&amp;quot;);;\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 StatisticInformation&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_13 : Speicher Status abfrage, BYD HV direkt&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 14_Lüfter_ein\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 15_Lüfter_aus\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 17 Wiederhole alle 180s das Kommando für die DcPowerAbs Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
17_Kommando_Wiederholung_DcPowerAbs\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [$SELF:SpeicherTriggerLaden] eq &amp;quot;An&amp;quot;  and                         ## Ist der Trigger für das Zwangsladen aktiv?\&lt;br /&gt;
       [$SELF:SpeicherDcPowerAbs]   ne 0     and                         ## Wurde eine Lade/Entlade Leistung eingestellt?\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot; ) {   ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs [$SELF:SpeicherDcPowerAbs]&amp;quot;);;\&lt;br /&gt;
   set_Exec(&amp;quot;17_Battery_EM_State&amp;quot;,30,&#039;::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;)&#039;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_17 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl alias WR_1_Speicher_1_ExternControl&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl comment Version 2023.06.21 14:00\&lt;br /&gt;
\&lt;br /&gt;
Hier können externe Trigger für die Ladung und Entladung Der Batterie gesetzt werden.\&lt;br /&gt;
Die Zeiten können z.B. durch den WeekDayTimer entsprechend an einen Stromtarif angepasst werden.\&lt;br /&gt;
Das reading SpeicherEntladung Automatik/Zeit/SpeicherTrigger ermöglicht es die Zeitsteuerung zu überschreiben.\&lt;br /&gt;
\&lt;br /&gt;
ExternTrigger\&lt;br /&gt;
Das reading dient dem Freigeben und Sperren der externen Trigger, z.B. um im Herbst/Winter das smart_laden zu steuern.\&lt;br /&gt;
Es verriegelt somit die Zeitsteuerung oder den SpeicherTrigger.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger \&lt;br /&gt;
Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API\&lt;br /&gt;
Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst\&lt;br /&gt;
SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung\&lt;br /&gt;
\&lt;br /&gt;
SpeicherTrigger:entladen,gesperrt\&lt;br /&gt;
Dieser Trigger kann durch ander Logik gesetzt werden.\&lt;br /&gt;
Auch hier wäre eine Zeitsteuerung denkbar, die entladen/gesperrt entsprechend umschaltet.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherZeitStart/SpeicherZeitEnde\&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.\&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.\&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.\&lt;br /&gt;
\&lt;br /&gt;
Speicher*ControlActive\&lt;br /&gt;
Das jeweilige reading aktiviert diese Teilkomponente für die Steuerung.\&lt;br /&gt;
Ein jeweiliges Speicher*ControlRunning signalisiert, ob gerade die Bedingungen erfüllt sind.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherCmdRepeatActive\&lt;br /&gt;
Es muss im WR die externe Speicher Steuerung aktiviert sein.\&lt;br /&gt;
Möchte man trotzdem die Sendung der ExternControl Kommandos stoppen, obwohl die Bedingungen erfüllt sind,\&lt;br /&gt;
kann man dieses reading zum Deaktivieren auf 0 setzen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMiddayControl\&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMaxSOCControl\&lt;br /&gt;
Es wird versucht den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMinSOC\&lt;br /&gt;
Dies gehört zur Basis Steuerung und schaltet den MinSOC von Sommer auf Winter Betrieb,\&lt;br /&gt;
um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl disable 0&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl readingList SpeicherExternTrigger SpeicherCmdRepeatActive SpeicherZeitStart SpeicherZeitEnde SpeicherEntladung SpeicherTrigger SpeicherMiddayControlActive SpeicherMidday_Inverter_Max_Power SpeicherMidday_MaxChargePowerAbs_morning SpeicherMidday_MaxChargePowerAbs_midday SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC SpeicherMidday_NotBefore SpeicherMinSOC_Sommer SpeicherMinSOC_Winter SpeicherMinSOC_fc1_Limit SpeicherMaxSOCControlActive SpeicherMaxSOC_Actual SpeicherMaxSOC_DayBefore SpeicherMaxSOC_fc1_Limit&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl setList SpeicherExternTrigger:frei,gesperrt SpeicherCmdRepeatActive:0,1 SpeicherZeitStart:time SpeicherZeitEnde:time SpeicherEntladung:Automatik,Zeit,Trigger SpeicherTrigger:entladen,gesperrt,none SpeicherMiddayControlActive:0,1 SpeicherMidday_Inverter_Max_Power:slider,3000,500,20000 SpeicherMidday_MaxChargePowerAbs_morning:slider,0,50,1000 SpeicherMidday_MaxChargePowerAbs_midday:slider,0,100,4700 SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC:slider,20,5,50 SpeicherMidday_NotBefore:time SpeicherMinSOC_Sommer:slider,5,1,20 SpeicherMinSOC_Winter:slider,5,1,20 SpeicherMinSOC_fc1_Limit:slider,7000,500,17000 SpeicherMaxSOCControlActive:0,1 SpeicherMaxSOC_Actual:slider,60,5,100 SpeicherMaxSOC_DayBefore:slider,15,5,100 SpeicherMaxSOC_fc1_Limit:slider,10000,2000,50000&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl sortby 122&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
#########################################################\&lt;br /&gt;
## &amp;quot;Spalte 0&amp;quot;|&amp;quot;Spalte 1&amp;quot;|&amp;quot;Spalte 2&amp;quot;|&amp;quot;Spalte 3&amp;quot;|&amp;quot;Spalte 4&amp;quot;|&amp;quot;Spalte 5&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / DcPowerAbs / Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_Speicher,smart_Laden_start,smart_Laden_beenden,smart_Laden_starten_WB_1,smart_Laden_beenden_WB_1,Kommando_Wiederholung,SOC_Calculation,Reset,DC_Power_Abs,Sommer,Winter,Speicher_voll,14_Luefter_ein,15_Luefter_aus,Status_WR_1_Speicher_1_BYD&amp;quot;) | widget([$SELF:SpeicherDcPowerAbs],&amp;quot;selectnumbers,-4500,250,4500,0,lin&amp;quot;).&amp;quot;W&amp;quot;.widget([$SELF:SpeicherTriggerLaden],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |[WR_1_API:Battery_EM_State]|([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and [WR_1_API:Battery_InternControl_MinHomeConsumption] == 30000)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;smart_Laden aktiv&amp;lt;/span&amp;gt;&#039;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Speicher&amp;lt;dd&amp;gt;Steuerung&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherEntladung],&amp;quot;uzsuDropDown,Automatik,Trigger,Zeit&amp;quot;) |&amp;quot;WB_1 Laden &amp;quot;.widget([$SELF:SpeicherWB_1_buffer],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|\&lt;br /&gt;
FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,&amp;quot;Laden&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Standby&amp;quot;,15,&amp;quot;red&amp;quot;,&amp;quot;Entladen&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_Status([WR_1:Act_state_of_charge],15,&amp;quot;red&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,49,&amp;quot;green&amp;quot;,&amp;quot;Speicher SOC&amp;quot;)|\&lt;br /&gt;
\&lt;br /&gt;
 FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],&amp;quot;orange&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],15,&amp;quot;red&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P]).&amp;quot; W&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([WR_1:Act_state_of_charge])).STY(::round([WR_1:Act_state_of_charge],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Trigger&amp;lt;dd&amp;gt;Status / ExternTrigger / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherTrigger],&amp;quot;uzsuDropDown,entladen,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherExternTrigger],&amp;quot;uzsuDropDown,frei,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherZeitStart],&amp;quot;time&amp;quot;) | widget([$SELF:SpeicherZeitEnde],&amp;quot;time&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Kommando Wiederholung&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherCmdRepeatActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherCmdRepeatRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMaxSOCControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMaxSOCControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Limit&amp;lt;dd&amp;gt;fc1_Limit / Minimum SOC Zeit / gestern / geplant&amp;lt;/dd&amp;gt;&amp;quot; |\&lt;br /&gt;
FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMaxSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;). widget([$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;) | ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot;)?(POSIX::strftime(&amp;quot;%H:%M&amp;quot;,::localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,&amp;quot;&amp;quot;)))).&amp;quot; &amp;quot;.[$SELF:SpeicherMaxSOC_MinSOC_MinSOC].&amp;quot; %&amp;quot;):&amp;quot;wartet&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_DayBefore])).STY(&amp;quot;gestern&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_DayBefore],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_Actual])).STY(&amp;quot;geplant&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_Actual],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMiddayControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMiddayControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Limits&amp;lt;dd&amp;gt;Inverter_Max_Power / Laden nicht vor / Start /Stop&amp;lt;br&amp;gt;MaxSOC morgens / Power morgens / Power mittags&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMidday_Inverter_Max_Power],&amp;quot;selectnumbers,1000,250,15000,0,lin&amp;quot;).&amp;quot;W&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:SpeicherMidday_MaxSOC],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; | widget([$SELF:SpeicherMidday_NotBefore],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_morning],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_start],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_midday],&amp;quot;selectnumbers,0,100,4700,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_stop],&amp;quot;time&amp;quot;).([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0)?&amp;quot;dynamisch&amp;quot;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MinSOC Steuerung&amp;lt;dd&amp;gt;fc1_Limit / Winter | Sommer /aktuell&amp;lt;/dd&amp;gt;&amp;quot;|\&lt;br /&gt;
 FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMinSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;).widget([$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;).&amp;quot;wh&amp;quot; |\&lt;br /&gt;
 widget([$SELF:SpeicherMinSOC_Winter],&amp;quot;selectnumbers,10,1,30,0,lin&amp;quot;).widget([$SELF:SpeicherMinSOC_Sommer],&amp;quot;selectnumbers,5,1,10,0,lin&amp;quot;).&amp;quot;%&amp;quot; |&amp;quot;&amp;quot;|[WR_1_API:Battery_InternControl_MinSoc].&amp;quot; %&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherCmdRepeatActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherCmdRepeatRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-11 17:23:40 SpeicherDcPowerAbs 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:13 SpeicherEntladung Automatik&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherExternTrigger none&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherMaxSOCControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOCControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOC_Actual 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMaxSOC_DayBefore 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_MinSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_Time NULL&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:38:43 SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:27 SpeicherMiddayControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMiddayControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:12 SpeicherMidday_Inverter_Max_Power 9000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-08 11:21:31 SpeicherMidday_MaxChargePowerAbs_midday 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:31 SpeicherMidday_MaxChargePowerAbs_morning 450&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:28 SpeicherMidday_MaxSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-03 09:21:27 SpeicherMidday_NotBefore 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 18:45:27 SpeicherMinSOC_Sommer 5&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:54 SpeicherMinSOC_Winter 20&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-15 08:04:40 SpeicherMinSOC_fc1_Limit 16000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:05 SpeicherTrigger entladen&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 16:10:24 SpeicherZeitEnde 19:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:41:25 SpeicherZeitStart 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 WB_1_smart_laden_before ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1 ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;&#039;&#039;&#039;disable 1&#039;&#039;&#039;&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_0_KSEM ModbusAttr 1 60 192.168.178.xyz:502 TCP&lt;br /&gt;
attr WR_0_KSEM DbLogExclude .*&lt;br /&gt;
attr WR_0_KSEM DbLogInclude Active_energy.*&lt;br /&gt;
attr WR_0_KSEM alias WR_0_KSEM&lt;br /&gt;
attr WR_0_KSEM comment Version 2021.04.07 12:00\&lt;br /&gt;
Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\&lt;br /&gt;
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\&lt;br /&gt;
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\&lt;br /&gt;
\&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\&lt;br /&gt;
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\&lt;br /&gt;
\&lt;br /&gt;
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
attr WR_0_KSEM dev-h-defPoll 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr WR_0_KSEM disable 0&lt;br /&gt;
attr WR_0_KSEM event-on-change-reading Active_energy.*,M_AC_Current_.*&lt;br /&gt;
attr WR_0_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr WR_0_KSEM icon measure_power&lt;br /&gt;
attr WR_0_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr WR_0_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr WR_0_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr WR_0_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40075-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr WR_0_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr WR_0_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr WR_0_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40084-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40086-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40087-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr WR_0_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr WR_0_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr WR_0_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40091-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40096-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr WR_0_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr WR_0_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr WR_0_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40101-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr WR_0_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr WR_0_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr WR_0_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr WR_0_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr WR_0_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h512-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr WR_0_KSEM obj-h512-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h516-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr WR_0_KSEM obj-h516-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr WR_0_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr WR_0_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr WR_0_KSEM obj-h8196-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr WR_0_KSEM obj-h8212-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr WR_0_KSEM obj-h8228-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr WR_0_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr WR_0_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_0_KSEM sortby 140&lt;br /&gt;
attr WR_0_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr WR_0_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===BYD HV Speicher (mit HTTPMOD)===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort wird mit KeyValue() (siehe oben) verwaltet.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Der BYD HV Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
 - Die erste Abfrage führt das Login durch&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num *&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
&lt;br /&gt;
======KeyValue() speichern======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline aufgerufen werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition WR_1_Speicher_1 (BYD HV)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1 HTTPMOD http://%IP-WR_1_Speicher_1%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr WR_1_Speicher_1 DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1 DbLogInclude BatteryInformation_TotalVoltage,BatteryInformation_SOC,BatteryInformation_SOC,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 authRetries 1&lt;br /&gt;
attr WR_1_Speicher_1 comment Version 2021.04.07 12:00&lt;br /&gt;
attr WR_1_Speicher_1 dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_Speicher_1 enableControlSet 0&lt;br /&gt;
attr WR_1_Speicher_1 enableCookies 1&lt;br /&gt;
attr WR_1_Speicher_1 event-on-change-reading auth_.*,Battery.*_.*,Device.*_.*,Installation.*_.*,Array_.*,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 event-on-update-reading Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr WR_1_Speicher_1 get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr WR_1_Speicher_1 get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr WR_1_Speicher_1 get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr WR_1_Speicher_1 get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr WR_1_Speicher_1 get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr WR_1_Speicher_1 get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr WR_1_Speicher_1 get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr WR_1_Speicher_1 get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr WR_1_Speicher_1 get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr WR_1_Speicher_1 get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr WR_1_Speicher_1 get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr WR_1_Speicher_1 get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr WR_1_Speicher_1 get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr WR_1_Speicher_1 get01-16Name Array_Main_Current&lt;br /&gt;
attr WR_1_Speicher_1 get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr WR_1_Speicher_1 get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr WR_1_Speicher_1 get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr WR_1_Speicher_1 get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr WR_1_Speicher_1 get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr WR_1_Speicher_1 get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr WR_1_Speicher_1 get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr WR_1_Speicher_1 get01-22Name Array_Main_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr WR_1_Speicher_1 get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-73Name Array_Main_Power&lt;br /&gt;
attr WR_1_Speicher_1 get01-80Name Array_Series_Battery&lt;br /&gt;
attr WR_1_Speicher_1 get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr WR_1_Speicher_1 get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get01Name RunData&lt;br /&gt;
attr WR_1_Speicher_1 get01RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get02Name StatisticInformation&lt;br /&gt;
attr WR_1_Speicher_1 get02RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get02URL http://%IP-WR_1_Speicher_1%/asp/StatisticInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr WR_1_Speicher_1 get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr WR_1_Speicher_1 get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03Name DeviceInformation&lt;br /&gt;
attr WR_1_Speicher_1 get03RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get03URL http://%IP-WR_1_Speicher_1%/asp/DeviceInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-37Name BatteryInformation_Power&lt;br /&gt;
attr WR_1_Speicher_1 get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr WR_1_Speicher_1 get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-9Name BatteryInformation_Current&lt;br /&gt;
attr WR_1_Speicher_1 get04DeleteIfUnmatched 1&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get04Name BatteryInformation&lt;br /&gt;
attr WR_1_Speicher_1 get04RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr WR_1_Speicher_1 get04URL http://%IP-WR_1_Speicher_1%/asp/Home.asp&lt;br /&gt;
attr WR_1_Speicher_1 get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr WR_1_Speicher_1 get05Name InstallationConfig&lt;br /&gt;
attr WR_1_Speicher_1 get05RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get05URL http://%IP-WR_1_Speicher_1%/asp/UserInfo.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Data ArrayNum=1&amp;amp;SeriesBatteryNum=4&lt;br /&gt;
attr WR_1_Speicher_1 get10Header01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 get10Header02 Referer: http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Header03 Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
attr WR_1_Speicher_1 get10Header04 Accept: text/html,application/xhtml+xml,application/xml&lt;br /&gt;
attr WR_1_Speicher_1 get10Name Test_Array&lt;br /&gt;
attr WR_1_Speicher_1 get10URL http://%IP-WR_1_Speicher_1%/goform/SetRunData&lt;br /&gt;
attr WR_1_Speicher_1 getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1 handleRedirects 1&lt;br /&gt;
attr WR_1_Speicher_1 httpVersion 1.1&lt;br /&gt;
attr WR_1_Speicher_1 icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1 reAuthRegex Unauthorized&lt;br /&gt;
attr WR_1_Speicher_1 reading01Name auth_qop&lt;br /&gt;
attr WR_1_Speicher_1 reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Name auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Name auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Name auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Regex %IP-WR_1_Speicher_1%&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Value ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1_Speicher_1&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Regex %auth_realm%&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Value auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Regex %auth_nonce%&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Value auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Regex %auth_opaque%&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Value auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Regex %auth_response%&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Value {my $NAME=&amp;quot;WR_1_Speicher_1&amp;quot;;;my $pw=KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;);; $pw =~ &#039;&amp;quot;&#039;.s/@/\\@/g.&#039;&amp;quot;&#039;;; md5_hex(md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.$pw).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:00000001:d789ea5b7e9a2377:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;));;}&lt;br /&gt;
attr WR_1_Speicher_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1 showBody 0&lt;br /&gt;
attr WR_1_Speicher_1 showError 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid01ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sid02Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid02ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid02URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sortby 121&lt;br /&gt;
attr WR_1_Speicher_1 stateFormat {sprintf(&amp;quot;Total_Charge_Energy: %.0f kWh&amp;lt;br&amp;gt;Total_Efficiency: %.1f %% Battery_EM_State: %s&amp;quot;, ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Efficiency&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;Battery_EM_State&amp;quot;,&amp;quot;&amp;quot;))}&lt;br /&gt;
attr WR_1_Speicher_1 userReadings Statistic_SpecificInformation_00_Date:Statistic_SpecificInformation_05_EndTime.* { CommandDeleteReading(undef, $NAME.&amp;quot; .*-.*&amp;quot;);;;; localtime()},\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Difference_Charge_Energy:Statistic_GeneralInformation_Total_Charge_Energy.*  {ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Efficiency:Statistic_GeneralInformation_Total_Charge_Energy.*  {round(((ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)+((ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Act_state_of_charge&amp;quot;,0)/100)*11)) / ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0))*100 , 2)}&lt;br /&gt;
attr WR_1_Speicher_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1                    BYD HV     HTTPMOD   LAN/WLAN               Speicher Details, auch über einzelne Zellen. Das kann man nur für den alten BYD HV verwenden.&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Verwendet von Plenticore zur Steuerung des Speichers&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
PV_Schedule                                   DOIF                             Startet regelmäßige Aktionen&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Das ist veraltet, da die KI_Prognose nun verwendet werden sollte.&lt;br /&gt;
   2 Stündlich von 07:00 bis 20:00&lt;br /&gt;
   2.1 WR_1_config module_1_covered                                              Schnee auf den Modulen (noch in der Entwicklungsphase)&lt;br /&gt;
   2.2 Solar_forecast() für fc0                                                  Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 zweimal am Tag&lt;br /&gt;
   3.1 Solar_forecast() für fc1                                                  Aktualisieren der fc1 Prognose&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
   4 alle 5 Minuten&lt;br /&gt;
   4.1 WR_2_API 04_auth_me                                                       Aktualisieren der Bilanz (es wird ein Event erzeugt)&lt;br /&gt;
   4.2 WR_1_API 04_auth_me                                                       Der Master Wechselrichter kommt zum Schluss, damit die SW_* readings auch von anderen&lt;br /&gt;
                                                                                 Wechselrichtern die richtigen Werte haben.&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Dies ist jetzt im WR_ctl Device enthalten&lt;br /&gt;
WR_*_config                                   DUMMY                            Konfiguration für Strings,Ausrichtung,Nennleistung,IP-Adressen,Forecast&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC               begrenzt dann morgens den MaxSOC&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday     und den MaxChargePowerAbs&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning    für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_1:Solar_middayhigh_fc0_start &amp;lt;&amp;gt; WR_1:Solar_middayhigh_fc0_stop      Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_1:Solar_middayhigh_fc0_stop                         Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====SVG====&lt;br /&gt;
In eventuellen SVGs die Device und reading Namen korrigieren&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== AW Definition PV_Schedule (DOIF)===&lt;br /&gt;
Aufgrund der Komplexität wurde die Speichersteuerung aus diesem Device entfernt und im Device PV_1_Speicher_1_ExternControl ausgelagert.&lt;br /&gt;
Weitere Neuerungen sind die Bereitstellung eines Schnee Faktors pro String für die Solar_forecast() Funktion, was aber bitte als Versuch anzusehen ist.&lt;br /&gt;
Für den Vergleich mit dem Solar_Foracast Modul wird der Forecast zwei mal aufgerufen und einmal davon ins DWD_Forecast_Test geschrieben.&lt;br /&gt;
Diese Beispiele können natürlich einfach herausgelöscht werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
\&lt;br /&gt;
   (get WR_2_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
   (get WR_1_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 5 und 21 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([05:00-21:00] and [:00])\&lt;br /&gt;
   ## Erste Versuche mit Schnee, wenn zuwenig Strom in den Modulen fließt wird ein Faktor von 0.1 gesetzt\&lt;br /&gt;
   ## WR_1_config forecast_factor_autocorrection muss auf 1 gesetzt sein, damit das berücksichtigt wird\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt;  8 &amp;amp;&amp;amp; $hour &amp;lt; 12)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_1_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_2_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 12 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_3_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_4_covered &amp;quot;.$y)})\&lt;br /&gt;
\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   ## Bei Schnee wurde der module_*_covered Faktor bereits am Vortag gesetzt.\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 regelmäßig die Bilanz aktualisieren, alle 5 Minuten außer um :00\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00])\&lt;br /&gt;
\&lt;br /&gt;
  (get WR_2_API 04_auth_me)\&lt;br /&gt;
  (get WR_1_API 04_auth_me)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])   ## 6172\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])         ## 4727\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5707\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 4717\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5241\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 3517\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState WR Status|Forecast 0|Forecast 1|Bilanz refresh&lt;br /&gt;
attr PV_Schedule comment Version 2021.04.19 12:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0,3:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4&lt;br /&gt;
attr PV_Schedule webCmdLabel Statistic :Forecast_0 :Forecast_1 :Bilanz :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc.*_.*_Rad1h,fc.*_.*_TTT,fc.*_.*_FF,fc.*_.*_Neff,fc.*_.*_R101,fc.*_.*_RRS1c,fc.*_.*_DD,fc.*_.*_N,fc.*_.*_VV,fc.*_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2022.08.20 12:00\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
FF      : Windspeed\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc.*_.*_[Rad1h|TTT|FF|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,FF,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz,fc.*_.*&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro event-on-update-reading ObsDate.*,fc.*_.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
attr Astro userReadings fc0_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
\&lt;br /&gt;
fc1_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))}&lt;br /&gt;
attr Astro verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
CREATE DEFINER=`fhemuser`@`%` PROCEDURE `dwd_load`(IN var_date DATE, IN display char(10))&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;br /&gt;
SET @date:= var_date;&lt;br /&gt;
-- die alte Tabelle löschen&lt;br /&gt;
DROP TABLE IF EXISTS dwdfull;&lt;br /&gt;
&lt;br /&gt;
-- eine neue Tabelle anlegen&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `dwdfull` (&lt;br /&gt;
  `TIMESTAMP` datetime NOT NULL,&lt;br /&gt;
  `year`   int NOT NULL,&lt;br /&gt;
  `month`  int NOT NULL,&lt;br /&gt;
  `day`    int NOT NULL,&lt;br /&gt;
  `hour`   int NOT NULL,&lt;br /&gt;
  `TTT`    float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `DD`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `VV`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `N`      float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Neff`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `R101`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `RRS1c`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunD1`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Rad1h`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAz`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAlt` float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `yield`  float  DEFAULT 0,&lt;br /&gt;
  `yield_max`  float  DEFAULT 0,&lt;br /&gt;
  `forecast`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  PRIMARY KEY (`TIMESTAMP`),&lt;br /&gt;
  INDEX (`TIMESTAMP`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=&#039;DWD Forecast&#039;;&lt;br /&gt;
&lt;br /&gt;
-- als erstes die Grundlegenden Daten mit Zeitstempeln erzeugen&lt;br /&gt;
-- Rad1h wird als erstes eingetragen&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc0 Rad1h ältere Werte eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
	 	       )&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc1 Rad1h Werte von morgen eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Mit update alle weiteren Spalten füllen&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAz&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t2  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t2.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAz&lt;br /&gt;
  SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAlt&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t6 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t6.VV&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t5.VV&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t7 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t7.DD&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t5.DD&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t8 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t8.TTT&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t5.TTT&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t9 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t9.R101&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t5.R101&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t10 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t10.N&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t5.N&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t11 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t11.RRS1c&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t5.RRS1c&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield from Plenticore with Accu&lt;br /&gt;
   -- start left join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    left JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end left join&lt;br /&gt;
   &lt;br /&gt;
   UNION  -- for left and right join&lt;br /&gt;
&lt;br /&gt;
   -- start right join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    right JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end right join&lt;br /&gt;
   &lt;br /&gt;
   -- UNION end&lt;br /&gt;
   &lt;br /&gt;
  ) t12 USING(TIMESTAMP)&lt;br /&gt;
SET tt.yield = t12.yield&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Ermittle Ertrags Maximum der letzten 30 Tage um die Prognose zu limitieren&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield_max&lt;br /&gt;
      SELECT hour,&lt;br /&gt;
             cast(max(yield) AS DECIMAL(6)) AS yield_max&lt;br /&gt;
      FROM dwdfull&lt;br /&gt;
      WHERE TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
      GROUP BY hour&lt;br /&gt;
   ) t2  USING(hour)&lt;br /&gt;
SET tt.yield_max = t2.yield_max&lt;br /&gt;
WHERE TIMESTAMP &amp;gt; @date&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
IF display = &#039;show&#039; THEN &lt;br /&gt;
  select * from dwdfull LIMIT 3000;&lt;br /&gt;
ELSE&lt;br /&gt;
  select now();&lt;br /&gt;
END IF&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose (nicht mehr aktuell)==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
====Wetter Forecast Grundlagen (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der &lt;br /&gt;
    Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deutscher Wetter Dienst (DWD) (nicht mehr aktuell)===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
====RAW Definition DWD_Forecast (nicht mehr aktuell)====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wurden einige extra Werte vom DWD abgefragt, die für das Solar_Forecast Modul verwendet werden. Dieses Modul ist noch in der experimental Phase (2021.02.23) und liefert noch nicht gleichwertige Ergebnisse. Ein Test zum vergleichen kann aber nicht schaden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc0_.*_Rad1h,fc0_.*_TTT,fc0_.*_Neff,fc0_.*_R101,fc0_.*_RRS1c,fc0_.*_DD,fc0_.*_N,fc0_.*_VV,fc0_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2023.01.05 12:40\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc0_.*_[Rad1h|TTT|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===99_myUtils.pm Funktionen===&lt;br /&gt;
====Solar_forecast() (nicht mehr aktuell)====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen, muss ein Dummy WR_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Letzte Neuerungen:&lt;br /&gt;
- IM WR_1_config kann man verbose auf &amp;gt;3 setzen und bekommt dann Log Meldungen&lt;br /&gt;
- Es wird eine Autokorrektur unterstützt. Aktivierung durch &amp;quot;setreading WR_1_config forecast_factor_autocorrection 1&amp;quot;&lt;br /&gt;
  Für die Datenbank Anbindung wird ein DbRep Device LogDBRep_PV_Forecast_SQL verwendet. Die RAW definition kommt gleich im Anschluss.&lt;br /&gt;
- Das SQL für die Berechnung des Faktors der Autokorrektur Verwendet Konfigurationsvariablen aus den DbRep Device.&lt;br /&gt;
- Bei der Autokorrektur wird auch eine Bedeckung von Schnee (Strom im String &amp;lt; 1A) berücksichtigt. (das ist noch in der Entwicklung)&lt;br /&gt;
  Dieser Faktor wird im PV_Schedule Device erzeugt und dann im &amp;quot;WR_1_config module_*_covered&amp;quot; für jeden String eingetragen.&lt;br /&gt;
  Das muss jeder individuell für seine Anlage anpassen!&lt;br /&gt;
- Für die 70% Regelung wird nun auch ein Middayhigh Trigger ermittelt und die jeweilige Start/Stop Zeit. Dies steht dann im WR_1 Device bei den Solar_* readings&lt;br /&gt;
- Es besteht auch die Möglichkeit die Solar_forecast() Funktion ohne Datenbank zu verwenden, dann ist bei den Parametern &amp;quot;none&amp;quot; zu übergeben und&lt;br /&gt;
  es muss auch die Autokorrektur abgeschaltet sein.&lt;br /&gt;
- Anstelle des Wechselrichter Devices kann nun auch ein beliebiges anderes Device angegeben werden, in das dann der Forecast geschrieben wird.&lt;br /&gt;
  Auch hier kann dann keine Autokorrektur verwendet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.06.14 15:20&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;        # Mit dieser Datenbank wird gearbeitet&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zur Kommunikation mit der LogDB verwendet und muss entsprechend konfiguriert sein&lt;br /&gt;
     my $logdevice   = &amp;quot; &amp;quot;   ;        # Das ist der Wechselrichter, oder ein anderes Device, in das die Prognose geschrieben wird&lt;br /&gt;
        $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;    # Der reading Name wird um 0 oder 1 verlängert&lt;br /&gt;
&lt;br /&gt;
     # Welcher Verbose Level ist gesetzt?&lt;br /&gt;
     my $verbose = AttrVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Gibt es einen festen Korrekturfaktor für jede Stunde?&lt;br /&gt;
     my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
     # Soll eine Autokorrektur gemacht werden? 0 = Nein 1 = Ja&lt;br /&gt;
     my $autocorrection          = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor_autocorrection&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Beim DWD wird der Wert für die Stunde erst am Ende der Stunde eingetragen&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     # Hier werden die Variablen vorbelegt&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry1h,$logentry4h,$logentryrest,$logentry,$i) = (0) x 9 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($module_covered,$Solar_Correction_Faktor_auto,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 6 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 06:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $logdbrep ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
       # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
       CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Setzen der Tageszähler und Merker&lt;br /&gt;
     $logentry            = 0 ;   # Summiert den Solar_Calculation Wert für den ganzen Tag&lt;br /&gt;
     $logentry4h          = 0 ;   # Summierung für die nächsten vier Stunden&lt;br /&gt;
     $logentryrest        = 0 ;   # Summierung für den Rest des Tages&lt;br /&gt;
&lt;br /&gt;
     my $middayhigh           = 0 ; # Ein Merker, ob das Tagesmaximum überschritten wird&lt;br /&gt;
     my $middayhigh_start     = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_stop      = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_tmp       = 0;&lt;br /&gt;
     my $middayhigh_start_tmp = 0;&lt;br /&gt;
     my $middayhigh_stop_tmp  = 0;&lt;br /&gt;
&lt;br /&gt;
     my $Inverter_Max_Power = ReadingsVal($logdevice.&amp;quot;_Speicher_1_ExternControl&amp;quot;,&amp;quot;SpeicherMidday_Inverter_Max_Power&amp;quot;,&amp;quot;unused&amp;quot;);  # Überschreiben des middayhigh&lt;br /&gt;
     if ($Inverter_Max_Power eq &amp;quot;unused&amp;quot;) {&lt;br /&gt;
       $Inverter_Max_Power = ReadingsVal($logdevice,&amp;quot;Inverter_Max_Power&amp;quot;,0) +500 ;      # Hier wird ein Durchschnittsverbrauch des Hauses aufaddiert&lt;br /&gt;
     } else {&lt;br /&gt;
       if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power manuell gesetzt&amp;quot; } ;&lt;br /&gt;
     };&lt;br /&gt;
     if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power auf &amp;quot;.$Inverter_Max_Power.&amp;quot; gesetzt&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
     # Es werden Stundenwerte von 06:00 bis 21:00 Uhr berechnet&lt;br /&gt;
     for ($i = 6; $i &amp;lt;= 21; $i++) {&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0 and $i == 6) {&lt;br /&gt;
         # Neuberechnung der stündlichen Autokorrektur Faktoren in der Datenbank. Das DbRep Device LogDBRep_PV_Forecast_SQL muss vorhanden sein.&lt;br /&gt;
         # Achtung, beim SQL muss &#039;@&#039; mit &#039;\@&#039; maskiert werden.&lt;br /&gt;
         CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking &amp;quot;.sprintf(&amp;quot;&lt;br /&gt;
               INSERT INTO history&lt;br /&gt;
                 (TIMESTAMP,DEVICE,READING,VALUE)&lt;br /&gt;
                  SELECT&lt;br /&gt;
                    TIMESTAMP,DEVICE,READING,VALUE&lt;br /&gt;
                  FROM (&lt;br /&gt;
                    SELECT&lt;br /&gt;
                      DATE_ADD(CURDATE(),INTERVAL t2.HOUR HOUR) AS TIMESTAMP,&lt;br /&gt;
                      t2.DEVICE,&lt;br /&gt;
                      \@readingname                             AS READING,&lt;br /&gt;
                      cast(if(avg(t2.FACTOR) &amp;gt; 1.6, 1.6,&lt;br /&gt;
                              avg(t2.FACTOR) ) AS DECIMAL(2,1)) AS VALUE&lt;br /&gt;
                    FROM (&lt;br /&gt;
                      SELECT * FROM (&lt;br /&gt;
                        SELECT&lt;br /&gt;
                          t1.TIMESTAMP,&lt;br /&gt;
                          t1.HOUR,&lt;br /&gt;
                          t1.DEVICE,&lt;br /&gt;
                          t1.READING,&lt;br /&gt;
                          t1.VALUE,&lt;br /&gt;
                          if(\@diff = 0,0, \@temp:=cast((t1.VALUE-\@diff) AS DECIMAL(8,2)))                                    AS DIFF,&lt;br /&gt;
                          if(((t1.VALUE+(-1*\@temp))*\@corr)=0,0, cast((t1.VALUE/(t1.VALUE+(-1*\@temp))*\@corr) AS DECIMAL(8,1))) AS FACTOR,&lt;br /&gt;
                          \@diff:=t1.VALUE                                                                                        AS curr_V&lt;br /&gt;
                        FROM (&lt;br /&gt;
                          SELECT&lt;br /&gt;
                            h.TIMESTAMP,&lt;br /&gt;
                            date(h.TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(h.TIMESTAMP) AS HOUR,&lt;br /&gt;
                            h.DEVICE,&lt;br /&gt;
                            h.READING,&lt;br /&gt;
                            h.VALUE&lt;br /&gt;
                          FROM history AS h&lt;br /&gt;
                          WHERE h.DEVICE    =  \@device&lt;br /&gt;
                            AND (h.READING  =  \@reading1 OR h.READING = \@reading2)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;gt;= DATE_SUB(DATE(now()),INTERVAL \@days DAY)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;lt;= CURDATE()&lt;br /&gt;
                            AND MINUTE(h.TIMESTAMP) = 0&lt;br /&gt;
                            AND h.VALUE &amp;gt;= 50&lt;br /&gt;
                          GROUP BY DATE,HOUR,h.READING,h.DEVICE,h.TIMESTAMP&lt;br /&gt;
                         )t1&lt;br /&gt;
                       )tx&lt;br /&gt;
                        WHERE READING != \@reading2&lt;br /&gt;
                          AND HOUR &amp;gt; 6&lt;br /&gt;
                     )t2&lt;br /&gt;
                      GROUP BY t2.HOUR,t2.DEVICE&lt;br /&gt;
                   )t3&lt;br /&gt;
                    WHERE&lt;br /&gt;
                      t3.VALUE != 0&lt;br /&gt;
                    ORDER BY TIMESTAMP&lt;br /&gt;
                    ON DUPLICATE KEY UPDATE&lt;br /&gt;
                      VALUE=t3.VALUE;&lt;br /&gt;
           &amp;quot;) # Ende sprintf()&lt;br /&gt;
         );   # Ende CommandGet()&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
       $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
       if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
         $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
&lt;br /&gt;
         $Solar_Rain = 0;&lt;br /&gt;
         for (my $r600 = $i+5; $r600 &amp;gt;= $i; $r600--) {&lt;br /&gt;
           $Solar_Rain        += ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($r600+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
         $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
         $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
         $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
         if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation.&amp;quot; W &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0).&amp;quot; J&amp;quot; } ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($cloudk ne 0) {&lt;br /&gt;
         $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
         $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($raink ne 0) {&lt;br /&gt;
         $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($tempk ne 0) {&lt;br /&gt;
         $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0) {&lt;br /&gt;
         $Solar_Correction_Faktor_auto = CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking SELECT VALUE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;Solar_Correction_Faktor_auto&#039; AND TIMESTAMP=&#039;&amp;quot;.sprintf(&amp;quot;%4d-%02d-%02d %02d:00:00&amp;quot;,$year,$mon,$mday,$i).&amp;quot;&#039;;&amp;quot;) ;&lt;br /&gt;
         if($Solar_Correction_Faktor_auto eq &amp;quot;&amp;quot;) { $Solar_Correction_Faktor_auto = 1; };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $logentry1h = 0 ;   # Summierung für eine Stunde zurücksetzen&lt;br /&gt;
&lt;br /&gt;
       # Es werden 5 Modul Ausrichtungen durchlaufen, der Name der Ausrichtung befindet sich z.B. in WR_1_config&lt;br /&gt;
       for(my $j=1;$j&amp;lt;=5;$j++){&lt;br /&gt;
         # lesen der Modul Anzahl&lt;br /&gt;
         $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
         if ($module_count[$j] ne 0) {&lt;br /&gt;
           # Für diese Ausrichtung sind Module Installiert&lt;br /&gt;
&lt;br /&gt;
           # Berechnung des Korrekturfaktors für die Modul Ausrichtung&lt;br /&gt;
           $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;factor/plain/direction       : &amp;quot;.$Solar_Plain.&amp;quot; &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) };&lt;br /&gt;
           # Berechnung der Modul Nennleistung für diese Ausrichtung&lt;br /&gt;
           $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
           # Anwendung der Korrekturfaktoren&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp   * $Solar_Correction_Cloud * $Solar_Correction_Rain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Faktor ;&lt;br /&gt;
&lt;br /&gt;
           if ($autocorrection ne 0) {&lt;br /&gt;
             # Nachsehen, ob dieser String mit Schnee bedeckt ist&lt;br /&gt;
             $module_covered = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_covered&amp;quot;,1) ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $Solar_Correction_Faktor_auto ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $module_covered ;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot;_covered             : &amp;quot;.$module_covered };&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Runden auf volle Watt Werte&lt;br /&gt;
           $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot; estimation          : &amp;quot;.$Solar_[$j] };&lt;br /&gt;
&lt;br /&gt;
           # Aufsummieren aller konfigurierter Ausrichtungen&lt;br /&gt;
           $logentry1h += $Solar_[$j] ; # Summe für eine Stunde (wird mit jedem lauf von $i wieder auf 0 gesetzt)&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe der nächsten 4 h gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour and $i &amp;lt;= $hour+3) {&lt;br /&gt;
             $logentry4h += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe für den Resttag gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour) {&lt;br /&gt;
             $logentryrest += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           $logentry += $Solar_[$j] ; # Summe für den ganzen Tag&lt;br /&gt;
&lt;br /&gt;
           # Den Forecast Wert für die aktuelle Stunde in das Wechselrichter Device schreiben&lt;br /&gt;
           if ($fc == 0 and $hour == $i) {&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;                   : &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; };&lt;br /&gt;
             CommandSetReading(undef, $logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j]) ;&lt;br /&gt;
           };&lt;br /&gt;
         };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Alle Forecast Werte für die jeweilige Stunde in die DbLog schreiben (Es wird der Cache verwendet)&lt;br /&gt;
&lt;br /&gt;
       if ( $logdb ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
         CommandSet(undef, $logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry1h.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry1h.&amp;quot;|&amp;quot;) ;&lt;br /&gt;
&lt;br /&gt;
         if ( $middayhigh == 0 and $logentry1h &amp;gt; $Inverter_Max_Power ) {&lt;br /&gt;
           $middayhigh           = 1;&lt;br /&gt;
           $middayhigh_start_tmp = $i-1;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;lt; $Inverter_Max_Power and $middayhigh_stop_tmp == 0 )  {&lt;br /&gt;
           $middayhigh_stop_tmp = $i;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;gt; $Inverter_Max_Power and $middayhigh_stop ne &amp;quot;00:00&amp;quot; )  {&lt;br /&gt;
           $middayhigh_stop_tmp = 0;                                # da war ein kurzer Einbruch, es sollte noch länger sein.&lt;br /&gt;
         };&lt;br /&gt;
         if ($middayhigh == 1 and&lt;br /&gt;
             $middayhigh_stop_tmp != 0 and&lt;br /&gt;
             $middayhigh_stop_tmp == $i ) {                                    # das Ende des Middayhigh wurde gefunden&lt;br /&gt;
&lt;br /&gt;
           $middayhigh_tmp = $middayhigh_stop_tmp - $middayhigh_start_tmp;&lt;br /&gt;
           if ( $middayhigh_tmp &amp;gt; 4 )  {                                       # das Middayhigh wird zu lang&lt;br /&gt;
             if ($verbose &amp;gt;= 3 ) {                                             # die bisherigen Zeiten ausgeben&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp) ;&lt;br /&gt;
             }&lt;br /&gt;
             $middayhigh_tmp       = round(($middayhigh_tmp/4)-0.2 ,0);        # die Rundung der Zeit zum Abziehen etwas verschieben&lt;br /&gt;
             $middayhigh_start_tmp = $middayhigh_start_tmp + $middayhigh_tmp;  # es wird um ganze Stunden verkürzt&lt;br /&gt;
             $middayhigh_stop_tmp  = $middayhigh_stop_tmp  - $middayhigh_tmp;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) {                                              # melde die Verkürzung&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;         : verkürzt um &amp;quot;.($middayhigh_tmp *2).&amp;quot; Stunden&amp;quot;;&lt;br /&gt;
             }&lt;br /&gt;
           };&lt;br /&gt;
           $middayhigh_start = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
           $middayhigh_stop  = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp);&lt;br /&gt;
           if ($verbose &amp;gt;= 3) {                                                # gib die finalen Zeiten aus&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.$middayhigh_start;&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.$middayhigh_stop ;&lt;br /&gt;
           }&lt;br /&gt;
         };&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ; # setz die Zeiten im Device&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Sobald mindestens ein String configuriert ist sollen diese Werte, der aktuellen Stunde, in das Wechselrichter Device geschrieben werden&lt;br /&gt;
       if ($fc == 0 and $hour == $i and $module_count[1] ne 0) {&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry1h) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Auch die Solar_Calculation jeder einzelnen Stunde wird als reading in das Wechselrichter Device geschrieben&lt;br /&gt;
       CommandSetReading(undef, sprintf(&amp;quot;%s %s_%02d %d&amp;quot;,$logdevice,$reading,$i,$logentry1h)) ;&lt;br /&gt;
&lt;br /&gt;
       # Für die Fehlersuche kommen noch einige Informationen ins Log&lt;br /&gt;
       if ($verbose &amp;gt;= 3) {&lt;br /&gt;
         Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Cloud                  : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;cloudk                       : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Cloud       : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Rain                   : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;raink                        : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Rain        : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Temp                   : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;tempk                        : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Temp        : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor      : &amp;quot;.$Solar_Correction_Faktor ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor_auto : &amp;quot;.$Solar_Correction_Faktor_auto ;&lt;br /&gt;
         Log 3, &amp;quot;Forecast,Hour,Estimation 1h  : &amp;quot;.$fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$logentry1h ;&lt;br /&gt;
       };&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Die Summe der nächsten 4 Stunden in das Wechselrichter Device schreiben&lt;br /&gt;
     if ($fc == 0) {&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_4h &amp;quot;.$logentry4h) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_rest &amp;quot;.$logentryrest) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_day &amp;quot;.$logentry) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $middayhigh == 0 ) {    # Auf Defaults zurücksetzen&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.02.28 17:00&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    my $verbose     = AttrVal(&amp;quot;Astro&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = CommandGet(undef, &amp;quot;Astro text SunAz &amp;quot;.$time) ;&lt;br /&gt;
    my $elevation   = CommandGet(undef, &amp;quot;Astro text SunAlt &amp;quot;.$time) ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain time             : &amp;quot;.$time;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain azimuth          : &amp;quot;.$azimuth;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain elevation        : &amp;quot;.$elevation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain orientation      : &amp;quot;.$orientation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain angle            : &amp;quot;.$angle;&lt;br /&gt;
    };&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.1798) {&lt;br /&gt;
      if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_Forecast_SQL (nicht mehr aktuell)====&lt;br /&gt;
Dieses Device war vormals das LogDBRep_PV_Forecast_SQL , es wird jedoch nun mehrfach verwendet und wurde deshalb umbenannt. Das LogDBRep_PV_Forecast_SQL kann gelöscht werden.&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
Für die Solar_forecast() Funktion wurden hier SQL Variablen Definiert, die für die Autokorrektur verwendet werden:&lt;br /&gt;
- @days ist die Anzahl der Tage, über die ein stündlicher, durchschnitts Korrektur Faktor berechnet wird.&lt;br /&gt;
- @corr ermöglicht es diesen Faktor nochmals zu verändern &amp;lt;1 dämpft, &amp;gt;1 verstärkt&lt;br /&gt;
- @device ist der Plenticore Wechselrichter&lt;br /&gt;
- @reading1 ist die reale DC Leistung ohne die Batterie, hier wird &#039;&#039;&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;&#039;&#039; für die Schwarm Implementierung verwendet.&lt;br /&gt;
- @reading2 wird der Basisname der readings im WR_1 Device&lt;br /&gt;
- @readingname wird der reading Name des Korrekturfaktors.&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
Durch die Erweiterung zum Schwarm mit mehreren AC-Quellen wurde die Variable @reading1 verändert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_Forecast_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL allowDeletion 1&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL room System&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdVars SET @days:=3, @corr:=0.7, @diff:=0, @temp:=0, @device:=&#039;WR_1&#039;, @reading1:=&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;, @reading2:=&#039;Solar_Calculation_fc0&#039;, @readingname:=&#039;Solar_Correction_Faktor_auto&#039; ;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solar Forcast Tests (nicht mehr aktuell)===&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Astro Device Test====&lt;br /&gt;
Bei diesem Test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() Test (nicht mehr aktuell)====&lt;br /&gt;
Diese Funktion kann man folgendermaßen testen. Für Log Meldungen muss man im &#039;&#039;&#039;Astro Device verbose auf 3&#039;&#039;&#039; oder größer stellen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung, das Dach hätte demnach also Süd/West Lage.&lt;br /&gt;
&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann Folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:51:27.312 3: Solar_plain azimuth          : 210.6&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain elevation        : 0.49916224518291&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain orientation      : 0.185004188774085&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain angle            : 0.785395141022061&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain factor           : 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurückgeliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_forecast() Test (nicht mehr aktuell)====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
Bei gesetztem &amp;quot;&#039;&#039;&#039;attr Astro verbose 3&#039;&#039;&#039;&amp;quot; erscheinen hier ebenfalls die Astro Log Informationen.&lt;br /&gt;
Durch setzen von &amp;quot;&#039;&#039;&#039;attr WR_1_config verbose 3&#039;&#039;&#039;&amp;quot; bekommt man die Log Meldungen vom Sorar_forecast()&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&lt;br /&gt;
generische Verwendung ohne DbLog/DbRep: &#039;&#039;&#039;Das Astro Device muss &amp;quot;Astro&amp;quot; heißen und das DWD Device muss &amp;quot;DWD_Forecast&amp;quot; heißen!!&#039;&#039;&#039;&lt;br /&gt;
{Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;&amp;lt;beliebiges Device&amp;gt;&amp;quot;,&amp;quot;&amp;lt;prefix für die readings&amp;gt;_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,[0|1])}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann solche Blöcke, die man zusammenhängend betrachten sollte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power manuell gesetzt&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power auf 7000 gesetzt&lt;br /&gt;
2021.04.07 15:57:23.932 3: Solar_SolarRadiation         : 17 W 60.00 J        &amp;lt;&amp;lt;&amp;lt; vom DWD gelieferte Prognose in Watt und Joul&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain azimuth          : 80.2                &amp;lt;&amp;lt;&amp;lt; Astro Informationen&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain orientation      : -0.171041608489249&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain factor           : 0.001               &amp;lt;&amp;lt;&amp;lt; Die Funktion ist noch außerhalb des Gültigkeitsbereiches&lt;br /&gt;
2021.04.07 15:57:23.977 3: factor/plain/direction       : 0.001 40/-90     &lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1_covered             : 1                   &amp;lt;&amp;lt;&amp;lt; Ein Faktor für die Schneebedeckung&lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1 estimation          : 0                   &amp;lt;&amp;lt;&amp;lt; Die erwartete Leistung liegt bei 0 Watt&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:23.991 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2_covered             : 1&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain orientation      : -1.94183189053337&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.002 3: factor/plain/direction       : 0.001 40/0&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.013 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.020 3: Solar_SolarRadiation         : 17                  &amp;lt;&amp;lt;&amp;lt; Rad1h ist 70 Watt&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Cloud                  : 70                  &amp;lt;&amp;lt;&amp;lt; 70 % Abdeckung des Himmels durch Wolken&lt;br /&gt;
2021.04.07 15:57:24.021 3: cloudk                       : -0.45 0             &amp;lt;&amp;lt;&amp;lt; Werte der Korrekturfunktion für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Correction_Cloud       : 0.685               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Rain                   : 152&lt;br /&gt;
2021.04.07 15:57:24.022 3: raink                        : -0.2 0&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Correction_Rain        : 0.696               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Regen&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Temp                   : 10.7                &amp;lt;&amp;lt;&amp;lt; Erwartete Temperatur an den Modulen (Schätzung) &lt;br /&gt;
2021.04.07 15:57:24.023 3: tempk                        : -0.39 25&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Temp        : 1.056               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für die Modultemperatur&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor      : 1                   &amp;lt;&amp;lt;&amp;lt; Fester Korrekturfaktor aus WR_1_config &lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor_auto : 0.5                 &amp;lt;&amp;lt;&amp;lt; Korrekturfaktor aus der Datenbank Berechnung der letzten Tage &lt;br /&gt;
2021.04.07 15:57:24.024 3: Forecast,Hour,Estimation 1h  : 0 7 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Forecast Basiseinstellung (nicht mehr aktuell)===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät WR_1_config von einer Ost/Süd/West Anlage mitgeliefert (setstate). Es werden bis zu 5 Strings unterstützt.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auch &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät WR_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch zusätzliche Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Berücksichtigung von Temperatur, Bewölkung und Regen (nicht mehr aktuell)===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das Ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
Durch die Autokorrektur ist nun auch ein Schnee Faktor dazu gekommen. Dieser wird im PV_Schedule Device &amp;quot;berechnet&amp;quot; :-) und und in das PV_1_config geschrieben. Bei aktivierter Autokorrektur wird dieser dann berücksichtigt.&lt;br /&gt;
=====Temperatur (nicht mehr aktuell)=====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Wolken und Regen (nicht mehr aktuell)=====&lt;br /&gt;
Aus den DWD_Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken Einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
===wunderground===&lt;br /&gt;
Dieser Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das kann dann als aktueller Wert in den Diagrammen angezeigt werden und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mit einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
&lt;br /&gt;
===RAW Definition Wetter_&amp;lt;Wohnort&amp;gt;===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;JSON&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;builtIn&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;datasource&amp;quot;: &amp;quot;-- Grafana --&amp;quot;,&lt;br /&gt;
        &amp;quot;enable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;iconColor&amp;quot;: &amp;quot;rgba(0, 211, 255, 1)&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Annotations &amp;amp; Alerts&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;dashboard&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;editable&amp;quot;: true,&lt;br /&gt;
  &amp;quot;gnetId&amp;quot;: null,&lt;br /&gt;
  &amp;quot;graphTooltip&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;id&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;links&amp;quot;: [],&lt;br /&gt;
  &amp;quot;panels&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P value&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;: &amp;quot;rgb(90, 90, 90)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid value&amp;quot;: &amp;quot;rgb(250, 250, 250)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_AC_Active_P&amp;quot;: &amp;quot;dark-orange&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P&amp;quot;: &amp;quot;semi-dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 0&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: false,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:78&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:79&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:80&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 10,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:81&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:82&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:83&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 5,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS &#039;SW_Total_DC_P&#039;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_grid\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_grid&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_PV\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_PV&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_Battery\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_Battery&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Actual_Battery_charge_usable_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Actual_Battery_charge_usable_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_AC_Active_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_AC_Active_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;A&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Leistungsbezug&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Heizung&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Heizung value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Pool&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Waschmaschine&amp;quot;: &amp;quot;light-red&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 12&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hideEmpty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;hideZero&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: true,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;connected&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true,&lt;br /&gt;
          &amp;quot;steppedLine&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P_Max&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  abs(avg(value)) AS \&amp;quot;Heizung\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;StromZaehler_Heizung&#039; AND\n  READING = &#039;SMAEM1901401955_Saldo_Wirkleistung&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;StromZaehler_Heizung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SMAEM1901401955_Saldo_Wirkleistung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Pool\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly02&#039; AND\n  READING = &#039;Power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly02&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Waschmaschine\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly03&#039; AND\n  READING = &#039;power&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly03&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Brunnen\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Brunnen&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Shaun\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_1&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Shaun&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hauptverbraucher&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0&amp;quot;: &amp;quot;super-light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0 value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1 value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East value&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South value&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West&amp;quot;: &amp;quot;light-purple&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West value&amp;quot;: &amp;quot;super-light-purple&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 13,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 24&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: null,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc0\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc0&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc1\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc1&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc1&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_sumOfAllPVInputs\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_sumOfAllPVInputs&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_DC_Sum&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Solar_Calculation\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_Ost\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_Ost&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_Ost&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_Ost&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_Sued\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_Sued&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_Sued&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_Sued&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Forecast/Prognose&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;16000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;refresh&amp;quot;: &amp;quot;5m&amp;quot;,&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 27,&lt;br /&gt;
  &amp;quot;style&amp;quot;: &amp;quot;dark&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [],&lt;br /&gt;
  &amp;quot;templating&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: []&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;time&amp;quot;: {&lt;br /&gt;
    &amp;quot;from&amp;quot;: &amp;quot;now-1d/d&amp;quot;,&lt;br /&gt;
    &amp;quot;to&amp;quot;: &amp;quot;now-1d/d&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timepicker&amp;quot;: {&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;refresh_intervals&amp;quot;: [&lt;br /&gt;
      &amp;quot;5s&amp;quot;,&lt;br /&gt;
      &amp;quot;10s&amp;quot;,&lt;br /&gt;
      &amp;quot;30s&amp;quot;,&lt;br /&gt;
      &amp;quot;1m&amp;quot;,&lt;br /&gt;
      &amp;quot;5m&amp;quot;,&lt;br /&gt;
      &amp;quot;15m&amp;quot;,&lt;br /&gt;
      &amp;quot;30m&amp;quot;,&lt;br /&gt;
      &amp;quot;1h&amp;quot;,&lt;br /&gt;
      &amp;quot;2h&amp;quot;,&lt;br /&gt;
      &amp;quot;1d&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timezone&amp;quot;: &amp;quot;utc&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;PV_Anlage_1&amp;quot;,&lt;br /&gt;
  &amp;quot;uid&amp;quot;: &amp;quot;W-Y51Dmgk&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: 105&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit SVG==&lt;br /&gt;
Die Diagramme werden bei mir nicht mehr weiterentwickelt, da ich auf Grafana umgestiegen bin. Sie stehen hier nur noch als Beispiele für den Anfang.&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Total_PV_P_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_Battery::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB WR_1:SW_Actual_battery_charge_usable_P::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_Max::&lt;br /&gt;
#LogDB WR_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:max_month_SW_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_&amp;lt;Wohnort&amp;gt;_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB WR_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_sumOfAllPVInputs::&lt;br /&gt;
#LogDB WR_1:Solar_Calculation::&lt;br /&gt;
#LogDB WR_1:Solar_East::&lt;br /&gt;
#LogDB WR_1:Solar_South::&lt;br /&gt;
#LogDB WR_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power_(sumOfAllPVInputs)&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV_Perl (DOIF Modul) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 1                                   ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                     ## Die LWP ist aus\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]           ## Die maximale Laufzeit der LWP ist noch nicht erreicht\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## Das Maximum des PV-Modus ist noch nicht erreicht\&lt;br /&gt;
     and [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]   ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : LWP on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;LWP_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;PV_Modus_Ein_LWP();;set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;)&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : LWP on for manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : LWP off after manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]          ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : LWP off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; 100                              ## es soll noch eine Reserve bleiben\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : LWP off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;gt; 0                                  ## läuft eine Wartezeit\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 5                                  ## läuft die Wartezeit bald ab\&lt;br /&gt;
     and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot;\&lt;br /&gt;
      and [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe läuft&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer LWP &amp;quot;.get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;)};;\&lt;br /&gt;
    del_Exec(&amp;quot;LWP_Ein_timer&amp;quot;);;                                           ## Die LWP wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
## Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_1_LWP_Nachheizen_WW\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [[$SELF:TimeEnd]]                                               ## Am Ende der möglichen PV Steuerung\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt;= 48                             ## wenn das Wasser noch nicht im Sollbereich ist\&lt;br /&gt;
     and\&lt;br /&gt;
        (   [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]        ## Die maximale Laufzeit der LWP/Tag ist noch nicht erreicht\&lt;br /&gt;
         or [LWP_Counter:countsPerDay] eq 0)                             ## oder die LWP ist noch gar nicht gelaufen\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_LWP_Nachheizen_WW&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP on for water heating&amp;quot;};;\&lt;br /&gt;
                                                                         ## Es wird die Soll Temperatur um die Hysterese angehoben \&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget &amp;quot;.(ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,48)+4));;\&lt;br /&gt;
                                                                         ## Das zurücksetzen auf den Standard von 50° erfolgt generell beim Abschalten\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Hohe Priorität im Winter für die LWP\&lt;br /&gt;
## Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_2_LWP_Prioritaet_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [WR_1:SW_Total_PV_P_reserve] &amp;gt;= 2000                            ## es besteht jedoch noch eine Reserve und der\&lt;br /&gt;
     and [shelly02:power_0] &amp;gt; 800                                        ## Pool wird gerade aufgeheizt, was im Winter auch in der Nacht passiert\&lt;br /&gt;
     and [WR_1:Act_state_of_charge] &amp;gt; 60                                 ## Der Speicher sollte schon 60 % gefüllt sein\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## und die WW Temperatur noch unter 60°\&lt;br /&gt;
     and [$SELF:LWP_Priority] eq &amp;quot;frei&amp;quot;                                  ## Aber nur einmal am Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_LWP_Prioritaet_An&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_2 : LWP Priorität&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___LWP_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
        or [$SELF:LWP_Status] eq &amp;quot;manuell&amp;quot;\&lt;br /&gt;
       )\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimeMin]\&lt;br /&gt;
     and ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___LWP_Ende&amp;quot;                           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 05__ : LWP run finished&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Priorität für LWP wieder frei geben, damit einmal am Tag der PV-Modus verwendet werden kann\&lt;br /&gt;
##\&lt;br /&gt;
06___LWP_Prioritaet_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [23:55]\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;06___LWP_Prioritaet_Reset&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 06__ : LWP Priorität frei&amp;quot;};;\&lt;br /&gt;
     set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;frei&amp;quot;);;                                 ## Der PV-Modus darf wieder verwendet weden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## In der Überganszeit wird die Heizung kurz vor der PV-Zeit wieder ein geschaltet\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_1_Heizung_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeStartHeizung]]                                        ## Einschalten der Heizung, damit aus dem Puffer nachgeheizt wird 02:03\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_1_Heizung_An&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_1 : LWP Heizung Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHeating Auto&amp;quot;);;                  ## Die Heizungssteuerung erfolgt wieder Automatisch\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_2_Heizung_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeEndHeizung]]                                          ## Abschalten der Heizung, damit der Puffer für morgens Heizreserve hat\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_2_Heizung_Aus&amp;quot;                        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 07_2 : LWP Heizung aus&amp;quot;};;\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;Heizung opModeHeating Off&amp;quot;);;                     ## Die Heizung wird komplett abgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
   if (    [WR_1:Solar_Calculation_fc1_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] ## Auch morgen ist das Wetter schlecht\&lt;br /&gt;
       and [Heizung:averageAmbientTemperature] &amp;lt;= 5.6 ) {                ## Die Heizgrenze ist schon ziemlich tief\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungWinter]);;    ## Im Winter bis in die Morgenstunden den Accu sparen\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 07_2 : Parameter: &amp;quot;.[WR_1:Solar_Calculation_fc1_day].&amp;quot; &amp;lt; &amp;quot;.[WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit].&amp;quot; and &amp;quot;.[Heizung:averageAmbientTemperature].&amp;quot; &amp;lt;= 5.6&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungUebergang]);; ## Bei schönerem Wetter erst später Heizen\&lt;br /&gt;
     }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_2 : TimeStartHeizung switched to &amp;quot;.[$SELF:TimeStartHeizung]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 15°\&lt;br /&gt;
##\&lt;br /&gt;
07_3_Heizung_WZ_15_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_3_Heizung_WZ_15_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_3 : Heizung WZ 15 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 15&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 22°\&lt;br /&gt;
##\&lt;br /&gt;
07_4_Heizung_WZ_22_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_4_Heizung_WZ_22_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_4 : Heizung WZ 22 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 22&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung aus\&lt;br /&gt;
##\&lt;br /&gt;
07_5_Warmwasser_aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_5_Warmwasser_aus&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_5 : LWP Warmwasser aus&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Off&amp;quot;);;                  ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation inactive&amp;quot;);;                      ## Zirkulation ebenfalls abschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung auf Automatik\&lt;br /&gt;
##\&lt;br /&gt;
07_6_Warmwasser_an\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_6_Warmwasser_an&amp;quot;                      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_6 : LWP Warmwasser Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Auto&amp;quot;);;                 ## Die Warmwassersteuerung erfolgt wieder automatisch\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation active&amp;quot;);;                        ## Zirkulation wieder einschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_LWP() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP on&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 60.0&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;verwendet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_LWP() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 50.0&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr LWP_PV_Perl DbLogExclude .*&lt;br /&gt;
attr LWP_PV_Perl DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV_Perl alias LWP_PV_Perl&lt;br /&gt;
attr LWP_PV_Perl comment Version 2023.01.18 09:00&lt;br /&gt;
attr LWP_PV_Perl disable 0&lt;br /&gt;
attr LWP_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV_Perl icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV_Perl room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV_Perl sortby 411&lt;br /&gt;
attr LWP_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|::ReadingsTimestamp(&amp;quot;Heizung&amp;quot;,&amp;quot;counterHeatQTotal&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Status / LWP Status / Brauchwasser&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,04_1_LWP_Nachheizen_WW,04_2_LWP_Prioritaet_An,05___LWP_Ende,06___LWP_Prioritaet_Reset,07_1_Heizung_An,07_2_Heizung_Aus,07_3_Heizung_WZ_15_Grad,07_4_Heizung_WZ_22_Grad,07_5_Warmwasser_aus,07_6_Warmwasser_an&amp;quot;) |[Heizung:opStateHeatPump1].&amp;quot; &amp;quot;.[Heizung:opStateHeatPump2]|[Heizung:opStateHeatPump3]|FUNC_Status([Heizung:hotWaterTemperature],47,&amp;quot;orange&amp;quot;,[Heizung:hotWaterTemperature],&amp;quot;green&amp;quot;,[Heizung:hotWaterTemperature],53,&amp;quot;red&amp;quot;,[Heizung:hotWaterTemperature]).&amp;quot; °C&amp;quot;\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;PV-Modus / Heiz-Modus / Winter, Übergangszeit Heiz Start/Ende&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;PV-Modus:&amp;lt;br&amp;gt;&amp;quot;.[$SELF:LWP_Priority].&amp;quot; / &amp;quot;.(([$SELF:LWP_Status] ne &amp;quot;Aus&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039;)|&amp;quot;Heizung: &amp;quot;.[Heizung:opModeHeating].&amp;quot;&amp;lt;br&amp;gt;Warmwasser: &amp;quot;.[Heizung:opModeHotWater]|widget([$SELF:TimeStartHeizungWinter],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartHeizungUebergang],&amp;quot;time&amp;quot;)|[$SELF:TimeStartHeizung].widget([$SELF:TimeEndHeizung],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;Statistiken&amp;quot;|&amp;quot;Zähler&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Information&amp;quot;|&amp;quot;Wert&amp;quot;\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;EVU&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[EVU_StromZaehler:Strom_Status-02])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;LWP/KWL&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung_Zaehler])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHeating])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Warmwasser&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHotWater])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Photovoltaik&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQPool])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQTotal])\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 23:55:00 LWP_Priority frei&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-29 15:37:06 LWP_Status Aus&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 12:21:48 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 3000&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 2250&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-25 19:00:12 RunTimeMin 2400&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:55:35 RunTimePerDay 28800&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:37 TimeEnd 15:05&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 13:24:01 TimeEndHeizung 18:35&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:19 TimeStart 11:30&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 18:35:00 TimeStartHeizung 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:37:59 TimeStartHeizungUebergang 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:34:08 TimeStartHeizungWinter 02:05&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-31 12:05:34 ui_command_1 ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.54&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP&lt;br /&gt;
attr shelly01 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 412&lt;br /&gt;
attr shelly01 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung_Zaehler&amp;quot;,0));;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Wärmepumpe Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly01 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{4}(\.[0-9]{1})*$ StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{1,3}(\.[0-9]{1})*$&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter comment Version 2021.01.09 11:16&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 413&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39071</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39071"/>
		<updated>2024-02-08T11:47:47Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erweiterung im PV_Schedule, um die Zählerstände zu speichern&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 1)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_2_API DbLogExclude .*&lt;br /&gt;
attr WR_2_API DbLogInclude Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API authRetries 1&lt;br /&gt;
attr WR_2_API comment Version 2021.04.27 16:00\&lt;br /&gt;
Passworte für die Abfrage des WR_2_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_2_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_2_API disable 0&lt;br /&gt;
attr WR_2_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_2_API enableControlSet 0&lt;br /&gt;
attr WR_2_API enableCookies 1&lt;br /&gt;
attr WR_2_API event-on-update-reading auth_.*,Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API get01Data %START%&lt;br /&gt;
attr WR_2_API get01Name 01_auth_start&lt;br /&gt;
attr WR_2_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API get02Data %FINISH%&lt;br /&gt;
attr WR_2_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_2_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API get03Data %SESSION%&lt;br /&gt;
attr WR_2_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_2_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_2_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_2_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_2_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_2_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_2_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_2_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get04JSON .&lt;br /&gt;
attr WR_2_API get04Name 04_auth_me&lt;br /&gt;
attr WR_2_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_2_API get05-1Name info_api_version&lt;br /&gt;
attr WR_2_API get05-2Name info_hostname&lt;br /&gt;
attr WR_2_API get05-3Name info_name&lt;br /&gt;
attr WR_2_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_2_API get05JSON .&lt;br /&gt;
attr WR_2_API get05Name 05_info_version&lt;br /&gt;
attr WR_2_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_2_API get20-10Format %.2f&lt;br /&gt;
attr WR_2_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-11Format %.2f&lt;br /&gt;
attr WR_2_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-12Format %.2f&lt;br /&gt;
attr WR_2_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-13Format %.2f&lt;br /&gt;
attr WR_2_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_2_API get20-14Format %.2f&lt;br /&gt;
attr WR_2_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_2_API get20-15Format %.2f&lt;br /&gt;
attr WR_2_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_2_API get20-16Format %.2f&lt;br /&gt;
attr WR_2_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_2_API get20-17Format %.2f&lt;br /&gt;
attr WR_2_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_2_API get20-18Format %.2f&lt;br /&gt;
attr WR_2_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_2_API get20-19Format %.2f&lt;br /&gt;
attr WR_2_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_2_API get20-1Format %.2f&lt;br /&gt;
attr WR_2_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_2_API get20-20Format %.2f&lt;br /&gt;
attr WR_2_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_2_API get20-21Format %.2f&lt;br /&gt;
attr WR_2_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_2_API get20-22Format %.2f&lt;br /&gt;
attr WR_2_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_2_API get20-23Format %.2f&lt;br /&gt;
attr WR_2_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_2_API get20-24Format %.2f&lt;br /&gt;
attr WR_2_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_2_API get20-25Format %.2f&lt;br /&gt;
attr WR_2_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_2_API get20-26Format %.2f&lt;br /&gt;
attr WR_2_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-27Format %.2f&lt;br /&gt;
attr WR_2_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-28Format %.2f&lt;br /&gt;
attr WR_2_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-29Format %.2f&lt;br /&gt;
attr WR_2_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_2_API get20-2Format %.2f&lt;br /&gt;
attr WR_2_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_2_API get20-30Format %.2f&lt;br /&gt;
attr WR_2_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_2_API get20-31Format %.2f&lt;br /&gt;
attr WR_2_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_2_API get20-32Format %.2f&lt;br /&gt;
attr WR_2_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_2_API get20-33Format %.2f&lt;br /&gt;
attr WR_2_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_2_API get20-34Format %.2f&lt;br /&gt;
attr WR_2_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_2_API get20-35Format %.2f&lt;br /&gt;
attr WR_2_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_2_API get20-36Format %.2f&lt;br /&gt;
attr WR_2_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_2_API get20-37Format %.2f&lt;br /&gt;
attr WR_2_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_2_API get20-38Format %.2f&lt;br /&gt;
attr WR_2_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_2_API get20-39Format %.2f&lt;br /&gt;
attr WR_2_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_2_API get20-3Format %.2f&lt;br /&gt;
attr WR_2_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_2_API get20-40Format %.2f&lt;br /&gt;
attr WR_2_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_2_API get20-41Format %.2f&lt;br /&gt;
attr WR_2_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_2_API get20-42Format %.2f&lt;br /&gt;
attr WR_2_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_2_API get20-43Format %.2f&lt;br /&gt;
attr WR_2_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_2_API get20-44Format %.2f&lt;br /&gt;
attr WR_2_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_2_API get20-45Format %.2f&lt;br /&gt;
attr WR_2_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_2_API get20-46Format %.2f&lt;br /&gt;
attr WR_2_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_2_API get20-47Format %.2f&lt;br /&gt;
attr WR_2_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_2_API get20-48Format %.2f&lt;br /&gt;
attr WR_2_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_2_API get20-49Format %.2f&lt;br /&gt;
attr WR_2_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_2_API get20-4Format %.2f&lt;br /&gt;
attr WR_2_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_2_API get20-50Format %.2f&lt;br /&gt;
attr WR_2_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_2_API get20-51Format %.2f&lt;br /&gt;
attr WR_2_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_2_API get20-52Format %.2f&lt;br /&gt;
attr WR_2_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_2_API get20-53Format %.2f&lt;br /&gt;
attr WR_2_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_2_API get20-54Format %.2f&lt;br /&gt;
attr WR_2_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_2_API get20-55Format %.2f&lt;br /&gt;
attr WR_2_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_2_API get20-56Format %.2f&lt;br /&gt;
attr WR_2_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_2_API get20-57Format %.2f&lt;br /&gt;
attr WR_2_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_2_API get20-58Format %.2f&lt;br /&gt;
attr WR_2_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_2_API get20-59Format %.2f&lt;br /&gt;
attr WR_2_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_2_API get20-5Format %.2f&lt;br /&gt;
attr WR_2_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_2_API get20-60Format %.2f&lt;br /&gt;
attr WR_2_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_2_API get20-61Format %.2f&lt;br /&gt;
attr WR_2_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_2_API get20-62Format %.2f&lt;br /&gt;
attr WR_2_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_2_API get20-63Format %.2f&lt;br /&gt;
attr WR_2_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_2_API get20-64Format %.2f&lt;br /&gt;
attr WR_2_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_2_API get20-65Format %.2f&lt;br /&gt;
attr WR_2_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_2_API get20-6Format %.2f&lt;br /&gt;
attr WR_2_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_2_API get20-7Format %.2f&lt;br /&gt;
attr WR_2_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_2_API get20-8Format %.2f&lt;br /&gt;
attr WR_2_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_2_API get20-9Format %.2f&lt;br /&gt;
attr WR_2_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_2_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_2_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_2_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_2_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get40Name 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable&lt;br /&gt;
attr WR_2_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_2_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_2_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_2_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get60Name 60_update_status&lt;br /&gt;
attr WR_2_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_2_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_2_API icon sani_solar&lt;br /&gt;
attr WR_2_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_2_API reading0101JSON nonce&lt;br /&gt;
attr WR_2_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_2_API reading0102JSON rounds&lt;br /&gt;
attr WR_2_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_2_API reading0103JSON salt&lt;br /&gt;
attr WR_2_API reading0103Name auth_salt&lt;br /&gt;
attr WR_2_API reading0104JSON transactionId&lt;br /&gt;
attr WR_2_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_2_API reading0201JSON signature&lt;br /&gt;
attr WR_2_API reading0201Name auth_signature&lt;br /&gt;
attr WR_2_API reading0202JSON token&lt;br /&gt;
attr WR_2_API reading0202Name auth_token&lt;br /&gt;
attr WR_2_API reading0301JSON message&lt;br /&gt;
attr WR_2_API reading0301Name info_message&lt;br /&gt;
attr WR_2_API reading0302JSON error&lt;br /&gt;
attr WR_2_API reading0302Name info_error&lt;br /&gt;
attr WR_2_API reading03JSON sessionId&lt;br /&gt;
attr WR_2_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_2_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_2_API replacement01Mode expression&lt;br /&gt;
attr WR_2_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_2_API replacement01Value {ReadingsVal(&amp;quot;WR_2_config&amp;quot;,&amp;quot;IP-WR_2&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement02Mode expression&lt;br /&gt;
attr WR_2_API replacement02Regex %START%&lt;br /&gt;
attr WR_2_API replacement02Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement04Mode expression&lt;br /&gt;
attr WR_2_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_2_API replacement04Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement05Mode expression&lt;br /&gt;
attr WR_2_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_2_API replacement05Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement06Mode reading&lt;br /&gt;
attr WR_2_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_2_API replacement06Value auth_signature&lt;br /&gt;
attr WR_2_API replacement07Mode reading&lt;br /&gt;
attr WR_2_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_2_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_2_API replacement08Mode expression&lt;br /&gt;
attr WR_2_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_2_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API replacement09Mode expression&lt;br /&gt;
attr WR_2_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_2_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set06Method POST&lt;br /&gt;
attr WR_2_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_2_API set06NoArg 1&lt;br /&gt;
attr WR_2_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_2_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_2_API set4002FollowGet 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_2_API set4002Method PUT&lt;br /&gt;
attr WR_2_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_2_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_2_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_2_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_2_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_2_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_2_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_2_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_2_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_2_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_2_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_2_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_2_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_2_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_2_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_2_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_2_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_2_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_2_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_2_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_2_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_2_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_2_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_2_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_2_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_2_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_2_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_2_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_2_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_2_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_2_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_2_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_2_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_2_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_2_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_2_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_2_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_2_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_2_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_2_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_2_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_2_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_2_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_2_API set50JSON .&lt;br /&gt;
attr WR_2_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_2_API set50ParseResponse 1&lt;br /&gt;
attr WR_2_API set50TextArg 1&lt;br /&gt;
attr WR_2_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_2_API showBody 1&lt;br /&gt;
attr WR_2_API showError 1&lt;br /&gt;
attr WR_2_API sid01Data %START%&lt;br /&gt;
attr WR_2_API sid01ParseResponse 1&lt;br /&gt;
attr WR_2_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API sid02Data %FINISH%&lt;br /&gt;
attr WR_2_API sid02ParseResponse 1&lt;br /&gt;
attr WR_2_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API sid03Data %SESSION%&lt;br /&gt;
attr WR_2_API sid03ParseResponse 1&lt;br /&gt;
attr WR_2_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API sortby 212&lt;br /&gt;
attr WR_2_API timeout 7&lt;br /&gt;
attr WR_2_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion Solar_forecast() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive        An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning       Aus = momentan keine Steuerung&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0          0 = Es gibt kein Mittags Hoch. Wird aus Solar_forecast() gesetzt &lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der PV_1:Solar_middayhigh_fc0_start wird dann unlimitiert bis zur PV_1:Solar_middayhigh_fc0_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_ExternControl DOIF ################################################################################################################\&lt;br /&gt;
## 1 Speicher Status vom WR_1_Speicher_1 aktualisieren.\&lt;br /&gt;
##   Dies geschieht über das WR_1_API Device, da der Speicher direkt am Wechselrichter angeschlossen ist.\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_WR_1_Speicher_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [:52]                                                           ## jede Stunde\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 21_Battery_Information&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 22_Battery_InternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 23_Battery_ExternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_1  : Speicher Status abfrage&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Wenn die Ladung im Herbst/Winter unter MinSoc geht allen PV Überschuss in die Batterie laden\&lt;br /&gt;
##\&lt;br /&gt;
## Im Winter kann der MinSoc, durch den WR Eigenverbrauch, unterschritten werden, deshalb wird vorher auf\&lt;br /&gt;
## smarte_laden umgeschaltet, bis die Batterie wieder einen hohen Soc erreicht hat. Siehe cmd_3 laden_beendet\&lt;br /&gt;
##\&lt;br /&gt;
2_smart_Laden_start_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [WR_ctl:Yield_fc0_day] &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit]     ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
       and [WR_1:Act_state_of_charge] &amp;lt;= [WR_1_API:Battery_InternControl_MinSoc]  ## Achtung der Speicherstand wird zu niedrig\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100             ## Der Speicher steht auf Entladen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.1: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.1: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_smart_Laden_start_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [WB_1:lp_1_ChargeStat]      eq &amp;quot;loading&amp;quot;                        ## Ein Fahrzeug wird gerade geladen\&lt;br /&gt;
     and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;Aus&amp;quot;                            ## Der Speicher darf nicht zum Laden verwendet werden\&lt;br /&gt;
     or\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot;                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot; ) {\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before aktiv&amp;quot;);;                ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before inaktiv&amp;quot;);;              ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
    } else {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_2.2: WallBox es wird gerade geladen&amp;quot;};;       ## Der vorherige Zustand war schon bekannt\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.2: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.2: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Beim erreichen von 90% Soc die Entladung wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:SpeicherEntladung] eq &amp;quot;Automatik&amp;quot;                            ## Nur für den Automatik Modus\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100         ## Das Speicher Entladen ist geperrt\&lt;br /&gt;
       and\&lt;br /&gt;
       [WR_1:Act_state_of_charge] &amp;gt;= 80                                  ## Der Speicher ist bereits 80% voll\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell aktiviert\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.1: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.1: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_smart_Laden_beenden_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;inaktiv&amp;quot;                      ## Vorher war es nicht aktiv\&lt;br /&gt;
      )\&lt;br /&gt;
     or  [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;                             ## Der Speicher darf zum Laden verwendet werden\&lt;br /&gt;
     or  [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                       ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.2: Batterie wird mit &amp;quot;.[?$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.2: Batterie auf &amp;quot;.[?WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (    [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;\&lt;br /&gt;
        and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;) {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF cmd_3.2: MaxSOC Limitierung wegen Wallboxnutzung abgeschaltet&amp;quot;;;}\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Wenn vor dem WB_1 laden das smart_Laden aktiv gewesen ist geht es zurück in den Zustand\&lt;br /&gt;
## \&lt;br /&gt;
3_smart_Laden_umschalten_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;aktiv&amp;quot;                        ## Vorher war es nicht aktiv\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_umschalten_WB_1&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                        ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: WB_1 laden beendet, reaktivieren des smart_Laden&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.3: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.3: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Bei Zeitsteuerung und guter Prognose bei 40% wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Zeit\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [$SELF:SpeicherEntladung]  eq &amp;quot;Zeit&amp;quot;                            ## Nur für den Zeit Modus\&lt;br /&gt;
     and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]            ## Zeitfenster aktiv ist\&lt;br /&gt;
     and [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                        ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (\&lt;br /&gt;
            [WR_1:Act_state_of_charge] &amp;gt;= 40                             ## und einem Stand von Soc 40%\&lt;br /&gt;
        and\&lt;br /&gt;
            ([WR_ctl:Yield_fc0_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit]   ## wenn es heute oder \&lt;br /&gt;
          or [WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit])  ## morgen viel Leistung gibt\&lt;br /&gt;
       )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_zeit&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, SpeicherExternTrigger, freigegeben&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Die Leistungsprognose von &amp;quot;.[$SELF:SpeicherMinSOC_fc1_Limit].&amp;quot; wird überschritten&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;frei&amp;quot;);;                         ## Trigger freigeben\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                           ## Signalisiere entladen im stateFormat\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);; ## Speicher für Entladung freigeben\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Freigabe der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. ([07:00-16:00]\&lt;br /&gt;
4_Trigger\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]       ## Zeitfenster aktiv ist\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot;                               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot; ) {                             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;  ## Speicher für Entladung freigeben\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                            ## Signalisiere entladen im stateFormat\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_4  : SpeicherExternTrigger, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Sperren der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. [16:00-07:00]\&lt;br /&gt;
5_Trigger_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitEnde]-[$SELF:SpeicherZeitStart]]       ## Zeitfenster verlassen wurde\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger_sperren&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;## Speicher für Entladung sperren\&lt;br /&gt;
  set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                             ## Signalisiere gesperrt im stateFormat\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
    {Log 3, &amp;quot;$SELF cmd_5  : SpeicherExternTrigger, Entlademodus gesperrt (Tarif oder Trigger)&amp;quot;};;\&lt;br /&gt;
 }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
6_Kommando_Wiederholung\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [WR_1_API:Battery_Control] &amp;gt; 0 and                                ## Wenn die ExternControl am WR konfiguriert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatActive]  eq &amp;quot;An&amp;quot; and                      ## Wenn die ExternControl Aktiviert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatRunning] eq &amp;quot;An&amp;quot; and                      ## Wenn es  ExternControl Kommandos zum Senden gibt\&lt;br /&gt;
       [  {sunrise_abs(&amp;quot;HORIZON=+5.0&amp;quot;,0,&amp;quot;6:00&amp;quot;,&amp;quot;08:35&amp;quot;)}                 ## Innerhalb der Photovoltaik Zeit\&lt;br /&gt;
        - {sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)} ] and\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot; ) {              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   my $MaxChargePowerTime = 0;;\&lt;br /&gt;
   my $MaxChargePowerAbs_midday = 0;;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {                              ## Hier können noch Testmeldungen hin\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : SpeicherMiddayControlRunning &amp;quot;.[$SELF:SpeicherMiddayControlRunning];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_start   &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_stop    &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop];;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlRunning] eq &amp;quot;An&amp;quot; ) {                  ## Wurde ein Mittagshoch ermittelt und aktiviert?\&lt;br /&gt;
\&lt;br /&gt;
     if ( [WR_1:Act_state_of_charge] &amp;gt;= [WR_1_API:Battery_InternControl_MinSoc] *3 ) {\&lt;br /&gt;
       if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs 0&amp;quot;);;     ## nicht vor z.B. 09:00 Uhr starten. Ladung auf 0 Watt setzen\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                                              ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot; Uhr noch nicht laden&amp;quot;;;\&lt;br /&gt;
         }\&lt;br /&gt;
       } else {                                                          ## Ist noch Vormittag?\&lt;br /&gt;
         if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
           ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning]);;\&lt;br /&gt;
           set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMidday_MaxSOC].&#039;)&#039;);;\&lt;br /&gt;
           if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                       ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; limitieren&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning].&amp;quot; limitiert&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSOC auf &amp;quot;.[$SELF:SpeicherMidday_MaxSOC].&amp;quot; % limitiert&amp;quot;;;\&lt;br /&gt;
           }\&lt;br /&gt;
         }\&lt;br /&gt;
       }\&lt;br /&gt;
     } else {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_6  : Battery_InternControl_MinSoc auf &amp;quot;.([WR_1_API:Battery_InternControl_MinSoc] *3).&amp;quot; % laden&amp;quot;;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
     if (::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) &amp;lt;= time and  ## Es ist Mittag\&lt;br /&gt;
         time &amp;lt;= ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
\&lt;br /&gt;
       my $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;)+3600 ));;\&lt;br /&gt;
          $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ));;\&lt;br /&gt;
\&lt;br /&gt;
       if ([$SELF:SpeicherMaxSOCControlRunning] eq &amp;quot;An&amp;quot; and                     ## Somit bleibt weniger Platz im Speicher und es ist\&lt;br /&gt;
           time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.$wait.&amp;quot;:00&amp;quot;) ) {  ## besser nicht zu früh beginnen.\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden wegen MaxSoc von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; auf &amp;quot;.$wait.&amp;quot; Uhr verschoben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
       } else {                                                                 ## auch jetzt nicht mit voller Leistung laden\&lt;br /&gt;
\&lt;br /&gt;
         if ([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0) {            ## dynamische Leistungsermittlung oder vorgewählter Wert\&lt;br /&gt;
           $MaxChargePowerTime       = ::round((::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) - time) / 3600 , 2);;  ## Mittags Ladezeit bestimmen\&lt;br /&gt;
\&lt;br /&gt;
           my $MaxChargePowerLimit   = (1 - ::round($MaxChargePowerTime,2) * [$SELF:SpeicherMidday_MaxChargePowerSteigung]);;  ## Zu Beginn etwas langsamer anfangen, empirisch ermittelt\&lt;br /&gt;
\&lt;br /&gt;
           $MaxChargePowerAbs_midday = ::round( [WR_1:Battery_work_capacity] * ([$SELF:SpeicherMaxSOC_Actual] - [WR_1:Act_state_of_charge]) / 100 * $MaxChargePowerLimit, 0);;\&lt;br /&gt;
\&lt;br /&gt;
           if ($MaxChargePowerAbs_midday &amp;lt; 500) { $MaxChargePowerAbs_midday = 500 };;## Nicht unter 1000\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Mittags $MaxChargePowerTime h mit $MaxChargePowerAbs_midday W laden&amp;quot;;;\&lt;br /&gt;
         } else {\&lt;br /&gt;
           $MaxChargePowerAbs_midday = [$SELF:SpeicherMidday_MaxChargePowerAbs_midday];; ## Nimm den vorgewählten Wert\&lt;br /&gt;
         };;\&lt;br /&gt;
\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs $MaxChargePowerAbs_midday&amp;quot;);;\&lt;br /&gt;
         set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMaxSOC_Actual].&#039;)&#039;);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; bis &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; freigegeben&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf $MaxChargePowerAbs_midday limitiert&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;\&lt;br /&gt;
         };;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
\&lt;br /&gt;
     if (time &amp;gt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {    ## Es ist Nachmittag und die\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                                         ## Mittagssteuerung wird abgeschaltet\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl nach &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; beendet&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;An&amp;quot; and ## Nur MaxSOC soll begrenzt werden\&lt;br /&gt;
       [$SELF:SpeicherMaxSOC_Actual] &amp;lt;= 100                        and                                          \&lt;br /&gt;
       ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;Aus&amp;quot;) { ##  sobald die Mittagssteuerung fertig ist\&lt;br /&gt;
     if ([WR_1:SW_Home_own_consumption_from_Battery] &amp;gt; 500) {             ## Sollte der Speicher bereits jetzt verwendet werden ist es besser\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                 ## die MaxSOC Begrenzung zu stoppen\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMaxSOCControl wegen Speicher Nutzung am Nachmittag beendet&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_6  : ExternControl Kommando Wiederholung erledigt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Bestimmung eines möglichen SOC für den nächsten Morgen und\&lt;br /&gt;
##   Vorbereitung für ein Leistungshoch am Mittag\&lt;br /&gt;
##\&lt;br /&gt;
7_SOC_Calculation\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       ([WR_1_API:Battery_Control] &amp;gt; 0 and                               ## Ist die ExternControl am WR aktiviert\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot;   or                ## Ist MaxSOC Limit konfiguriert\&lt;br /&gt;
         [$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; ) and               ## Ist Midday Kontrolle konfiguriert\&lt;br /&gt;
        [$SELF:SpeicherMaxSOC_MinSOC_Time]  eq &amp;quot;NULL&amp;quot; and                ## Wurde ein minimum SOC bereits ermittelt\&lt;br /&gt;
        [{sunrise_abs(&amp;quot;HORIZON=+4.0&amp;quot;,0,&amp;quot;5:50&amp;quot;,&amp;quot;08:35&amp;quot;)} - 10:00 ] and\&lt;br /&gt;
        [WR_1:SW_Home_own_consumption_from_PV] == [WR_1:SW_Home_own_consumption] ## Die PV Leistung reicht für&#039;s Haus\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot; ) {                     ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   my $MinSOC_Time   = &amp;quot;gefunden&amp;quot;;;                                       ## Nur einmal am Tag bearbeiten\&lt;br /&gt;
   my $MinSOC_MinSOC = ::round([WR_1:Act_state_of_charge],0);;            ## Festgestellter MinSOC am Morgen          Magic ???\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,$MinSOC_Time);;\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,$MinSOC_MinSOC);;\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                               ## merken und melden\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_MinSOC_Time &amp;quot;.$MinSOC_Time.&amp;quot; &amp;quot;.$MinSOC_MinSOC.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot; and\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt; 100 and     ## Der Speicher darf nicht im smart_laden sein\&lt;br /&gt;
       [Pool_Counter:countsPerDay] == 0 and                              ## Achtung der Pool und auch die LWP\&lt;br /&gt;
       [LWP_Counter:countsPerDay]  == 0 ) {                              ##    sollten nicht mehr früh morgens laufen\&lt;br /&gt;
\&lt;br /&gt;
     my $SpeicherSOCMinimum = [WR_1_API:Battery_InternControl_MinSoc]*3;; ## 3x MinSOC als reserve vorsehen\&lt;br /&gt;
     my $SpeicherSOCDayBefore = ::round(ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;, 100),0);; ## wie voll war er gestern noch?\&lt;br /&gt;
     my $SpeicherSOCNew       = 0;;\&lt;br /&gt;
     my $SpeicherSOCDelta     = 0;;\&lt;br /&gt;
\&lt;br /&gt;
     if ([WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMaxSOC_fc1_Limit] and\&lt;br /&gt;
         $MinSOC_MinSOC                   &amp;gt; $SpeicherSOCMinimum ) {      ## Ist der Speicher voller als er müsste?\&lt;br /&gt;
\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Leistung Prognose &amp;quot;.[WR_ctl:Yield_fc1_day].&amp;quot; wh &amp;gt; Schwellwert &amp;quot;.[$SELF:SpeicherMaxSOC_fc1_Limit].&amp;quot; wh&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Speicherladung aktuell $MinSOC_MinSOC % &amp;gt; Minimum $SpeicherSOCMinimum %&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
       $SpeicherSOCDelta = $MinSOC_MinSOC - $SpeicherSOCMinimum;;         ## Was wäre noch übrig?\&lt;br /&gt;
       if ($SpeicherSOCDelta &amp;lt;= 10) {                                    ## Das lohnt sich nicht\&lt;br /&gt;
         $SpeicherSOCNew = $SpeicherSOCDayBefore;;                        ## den Wert von gestern einfach beibehalten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCDayBefore);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; % gesichert&amp;quot;};;\&lt;br /&gt;
       } else {\&lt;br /&gt;
         $SpeicherSOCNew = ::round(($SpeicherSOCDayBefore+$SpeicherSOCDayBefore-$SpeicherSOCDelta)/2 ,0);;  ## um den Durchschnitt verringern\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCNew);;           ## Das soll heute in den Speicher\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCNew.&amp;quot; % neu berechnet und gesichert&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
       if ($SpeicherSOCNew &amp;gt; 0) {                                        ## Es gibt einen neuen MaxSoc\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;               ## Senden starten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Wiederholung starten\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual &amp;quot;.$SpeicherSOCNew.&amp;quot; % geplant&amp;quot;};;\&lt;br /&gt;
       } else {                                                          ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
     } else {                                                            ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
       if ($MinSOC_MinSOC  &amp;lt; $SpeicherSOCMinimum ) {                     ## MaxSoc leicht erhöhen, da er etwas zu niedrig war\&lt;br /&gt;
         $SpeicherSOCNew   = ::round($SpeicherSOCDayBefore+$SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         $SpeicherSOCDelta = ::round($SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,$SpeicherSOCNew);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore wurde um &amp;quot;.$SpeicherSOCDelta.&amp;quot; erhöht&amp;quot;};;\&lt;br /&gt;
       }\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt, da die Prognose für morgen zu schlecht ist&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; and                   ## Soll für mittags noch Platz gehalten werden?\&lt;br /&gt;
       [WR_ctl:Yield_fc0_middayhigh] == 1 ) {                                                    \&lt;br /&gt;
																	                           \&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Die Mittagskontrolle aktivieren\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){                              ## (die Uhrzeiten wurden bereits durch Solar_forecast() im WR_1 Device eingetragen)\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie SpeicherMiddayControlRunning vorbereitet&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_start &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_start&amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_stop  &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_stop &amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {                                                              ## Kein Mittagshoch\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMiddayControl es wird kein Middayhigh geben&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Reset der ExternControl Kommandos\&lt;br /&gt;
##\&lt;br /&gt;
8_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;16:00&amp;quot;,&amp;quot;21:00&amp;quot;)}]                ## hier sollte das Ende der PV-Zeit sein\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot;                                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot; ) {                               ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
																			                   \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Max SOC Steuerung zurücksetzen\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                           ## SpeicherMaxSOC_Actual auf Default\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,[WR_1:Act_state_of_charge]);;   ## Den vor Tages Wert merken\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,&amp;quot;NULL&amp;quot;);;                     ## Die MinSOC Time löschen\&lt;br /&gt;
																						       \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Midday Steuerung zurücksetzen\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_8  : ExternControl zurückgesetzt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird, das ist dann im Herbst/Winter\&lt;br /&gt;
##\&lt;br /&gt;
9_MinSOC_Winter\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit] and        ## Wenn morgen das Minimum an Leistung nicht erreicht wird\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;lt; [$SELF:SpeicherMinSOC_Winter]    and        ## und der MinSoc unter der Winter Wert eingestellt ist\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot; or\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;NULL&amp;quot; and [10:01])\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Winter]);;        ## Den MinSOC anheben, um eine eventuelle\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : Batterie MinSoc auf Winterbetrieb&amp;quot;};;        ## Notladung zu verhindern\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Im Winter Betrieb keine MaxSOC Begrenzung\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## und keine Midday Steuerung\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : MaxSOC Begrenzung und Midday Steuerung im Winterbetrieb deaktiviert&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Umschaltung des MinSoc wenn viel Leistung erwartet wir, das wäre dann Frühling/Sommer\&lt;br /&gt;
##\&lt;br /&gt;
10_MinSOC_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit] and         ## sobald viel Ladung erwartet wird und der MinSoc noch\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;gt; [$SELF:SpeicherMinSOC_Sommer]    and         ## noch im Winter Modus ist\&lt;br /&gt;
        [10:09] \&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
                                                                                           \&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Sommer]);;        ## den MinSOC auf Sommerbetrieb herabsetzen, es kann\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_10 : Batterie MinSoc auf Sommerbetrieb&amp;quot;};;                              ## wieder mehr Leistung genutzt werden\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Der Speicher ist voll geladen. Hier wird das ständige nachladen auf 100 % vermieden.\&lt;br /&gt;
##\&lt;br /&gt;
11_Speicher_voll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ( [WR_ctl:Yield_fc0_day]        &amp;gt;  [$SELF:SpeicherMaxSOC_fc1_Limit] and    ## 1) sobald viel Leistung erwartet wird und der Speicher voll ist\&lt;br /&gt;
         [WR_1:Act_state_of_charge]    == 100                              and    ##    den MaxSOC wieder reduzieren, damit nicht immer nachgeladen wird\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_Actual] ne 95                                      ##   \&lt;br /&gt;
        or\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_Actual] == 95 and                                  ## 2) oder das Nachladen gestoppt wurde\&lt;br /&gt;
         [WR_1:Act_state_of_charge] &amp;lt;=  98  and                                   ##    und der SOC unte 98 % gefallen ist\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,-7200,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)}])                    ##    zwei Stunden vor Sonnenuntergang eventuell wieder nachladen\&lt;br /&gt;
       ) and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot; ) {                       ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([WR_1:Act_state_of_charge] &amp;lt;= 98) {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                         ## Eventuell noch mal nachladen\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 100 % nachladen&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;95&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                       ## Start regelmäßiges senden der Kommandos\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## MaxSOC Begrenzung weil Speicher bereits 100 % hat\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 95 % reduziert&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 WR_1_Speicher_1 DC_Power_Abs setzen z.B. zur Zwangsentladung\&lt;br /&gt;
##     dies muss manuell wiederholt werden. Danach hängt es vom WR ab, wie er die Speichersteuerung fortsetzt.\&lt;br /&gt;
12_DC_Power_Abs \&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot;                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot; ) {                        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs &amp;quot;.[$SELF:SpeicherDcPowerAbs]);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_12 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 13 WR_1_Speicher_1 Status aktualisieren.\&lt;br /&gt;
##   Dies ist momentan nur für den BYD HV Speicher, da der BYD HVS eine direkte Abfrage nicht unterstützt.\&lt;br /&gt;
##   Wer keinen BYD HV Speicher hat kann das löschen\&lt;br /&gt;
13_Status_WR_1_Speicher_1_BYD\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
      or\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot; ) {          ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 BatteryInformation&amp;quot;);;\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 StatisticInformation&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_13 : Speicher Status abfrage, BYD HV direkt&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 14_Lüfter_ein\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 15_Lüfter_aus\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 17 Wiederhole alle 180s das Kommando für die DcPowerAbs Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
17_Kommando_Wiederholung_DcPowerAbs\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [$SELF:SpeicherTriggerLaden] eq &amp;quot;An&amp;quot;  and                         ## Ist der Trigger für das Zwangsladen aktiv?\&lt;br /&gt;
       [$SELF:SpeicherDcPowerAbs]   ne 0     and                         ## Wurde eine Lade/Entlade Leistung eingestellt?\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot; ) {   ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs [$SELF:SpeicherDcPowerAbs]&amp;quot;);;\&lt;br /&gt;
   set_Exec(&amp;quot;17_Battery_EM_State&amp;quot;,30,&#039;::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;)&#039;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_17 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl alias WR_1_Speicher_1_ExternControl&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl comment Version 2023.06.21 14:00\&lt;br /&gt;
\&lt;br /&gt;
Hier können externe Trigger für die Ladung und Entladung Der Batterie gesetzt werden.\&lt;br /&gt;
Die Zeiten können z.B. durch den WeekDayTimer entsprechend an einen Stromtarif angepasst werden.\&lt;br /&gt;
Das reading SpeicherEntladung Automatik/Zeit/SpeicherTrigger ermöglicht es die Zeitsteuerung zu überschreiben.\&lt;br /&gt;
\&lt;br /&gt;
ExternTrigger\&lt;br /&gt;
Das reading dient dem Freigeben und Sperren der externen Trigger, z.B. um im Herbst/Winter das smart_laden zu steuern.\&lt;br /&gt;
Es verriegelt somit die Zeitsteuerung oder den SpeicherTrigger.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger \&lt;br /&gt;
Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API\&lt;br /&gt;
Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst\&lt;br /&gt;
SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung\&lt;br /&gt;
\&lt;br /&gt;
SpeicherTrigger:entladen,gesperrt\&lt;br /&gt;
Dieser Trigger kann durch ander Logik gesetzt werden.\&lt;br /&gt;
Auch hier wäre eine Zeitsteuerung denkbar, die entladen/gesperrt entsprechend umschaltet.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherZeitStart/SpeicherZeitEnde\&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.\&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.\&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.\&lt;br /&gt;
\&lt;br /&gt;
Speicher*ControlActive\&lt;br /&gt;
Das jeweilige reading aktiviert diese Teilkomponente für die Steuerung.\&lt;br /&gt;
Ein jeweiliges Speicher*ControlRunning signalisiert, ob gerade die Bedingungen erfüllt sind.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherCmdRepeatActive\&lt;br /&gt;
Es muss im WR die externe Speicher Steuerung aktiviert sein.\&lt;br /&gt;
Möchte man trotzdem die Sendung der ExternControl Kommandos stoppen, obwohl die Bedingungen erfüllt sind,\&lt;br /&gt;
kann man dieses reading zum Deaktivieren auf 0 setzen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMiddayControl\&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMaxSOCControl\&lt;br /&gt;
Es wird versucht den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMinSOC\&lt;br /&gt;
Dies gehört zur Basis Steuerung und schaltet den MinSOC von Sommer auf Winter Betrieb,\&lt;br /&gt;
um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl disable 0&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl readingList SpeicherExternTrigger SpeicherCmdRepeatActive SpeicherZeitStart SpeicherZeitEnde SpeicherEntladung SpeicherTrigger SpeicherMiddayControlActive SpeicherMidday_Inverter_Max_Power SpeicherMidday_MaxChargePowerAbs_morning SpeicherMidday_MaxChargePowerAbs_midday SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC SpeicherMidday_NotBefore SpeicherMinSOC_Sommer SpeicherMinSOC_Winter SpeicherMinSOC_fc1_Limit SpeicherMaxSOCControlActive SpeicherMaxSOC_Actual SpeicherMaxSOC_DayBefore SpeicherMaxSOC_fc1_Limit&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl setList SpeicherExternTrigger:frei,gesperrt SpeicherCmdRepeatActive:0,1 SpeicherZeitStart:time SpeicherZeitEnde:time SpeicherEntladung:Automatik,Zeit,Trigger SpeicherTrigger:entladen,gesperrt,none SpeicherMiddayControlActive:0,1 SpeicherMidday_Inverter_Max_Power:slider,3000,500,20000 SpeicherMidday_MaxChargePowerAbs_morning:slider,0,50,1000 SpeicherMidday_MaxChargePowerAbs_midday:slider,0,100,4700 SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC:slider,20,5,50 SpeicherMidday_NotBefore:time SpeicherMinSOC_Sommer:slider,5,1,20 SpeicherMinSOC_Winter:slider,5,1,20 SpeicherMinSOC_fc1_Limit:slider,7000,500,17000 SpeicherMaxSOCControlActive:0,1 SpeicherMaxSOC_Actual:slider,60,5,100 SpeicherMaxSOC_DayBefore:slider,15,5,100 SpeicherMaxSOC_fc1_Limit:slider,10000,2000,50000&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl sortby 122&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
#########################################################\&lt;br /&gt;
## &amp;quot;Spalte 0&amp;quot;|&amp;quot;Spalte 1&amp;quot;|&amp;quot;Spalte 2&amp;quot;|&amp;quot;Spalte 3&amp;quot;|&amp;quot;Spalte 4&amp;quot;|&amp;quot;Spalte 5&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / DcPowerAbs / Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_Speicher,smart_Laden_start,smart_Laden_beenden,smart_Laden_starten_WB_1,smart_Laden_beenden_WB_1,Kommando_Wiederholung,SOC_Calculation,Reset,DC_Power_Abs,Sommer,Winter,Speicher_voll,14_Luefter_ein,15_Luefter_aus,Status_WR_1_Speicher_1_BYD&amp;quot;) | widget([$SELF:SpeicherDcPowerAbs],&amp;quot;selectnumbers,-4500,250,4500,0,lin&amp;quot;).&amp;quot;W&amp;quot;.widget([$SELF:SpeicherTriggerLaden],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |[WR_1_API:Battery_EM_State]|([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and [WR_1_API:Battery_InternControl_MinHomeConsumption] == 30000)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;smart_Laden aktiv&amp;lt;/span&amp;gt;&#039;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Speicher&amp;lt;dd&amp;gt;Steuerung&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherEntladung],&amp;quot;uzsuDropDown,Automatik,Trigger,Zeit&amp;quot;) |&amp;quot;WB_1 Laden &amp;quot;.widget([$SELF:SpeicherWB_1_buffer],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|\&lt;br /&gt;
FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,&amp;quot;Laden&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Standby&amp;quot;,15,&amp;quot;red&amp;quot;,&amp;quot;Entladen&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_Status([WR_1:Act_state_of_charge],15,&amp;quot;red&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,49,&amp;quot;green&amp;quot;,&amp;quot;Speicher SOC&amp;quot;)|\&lt;br /&gt;
\&lt;br /&gt;
 FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],&amp;quot;orange&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],15,&amp;quot;red&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P]).&amp;quot; W&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([WR_1:Act_state_of_charge])).STY(::round([WR_1:Act_state_of_charge],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Trigger&amp;lt;dd&amp;gt;Status / ExternTrigger / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherTrigger],&amp;quot;uzsuDropDown,entladen,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherExternTrigger],&amp;quot;uzsuDropDown,frei,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherZeitStart],&amp;quot;time&amp;quot;) | widget([$SELF:SpeicherZeitEnde],&amp;quot;time&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Kommando Wiederholung&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherCmdRepeatActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherCmdRepeatRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMaxSOCControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMaxSOCControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Limit&amp;lt;dd&amp;gt;fc1_Limit / Minimum SOC Zeit / gestern / geplant&amp;lt;/dd&amp;gt;&amp;quot; |\&lt;br /&gt;
FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMaxSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;). widget([$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;) | ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot;)?(POSIX::strftime(&amp;quot;%H:%M&amp;quot;,::localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,&amp;quot;&amp;quot;)))).&amp;quot; &amp;quot;.[$SELF:SpeicherMaxSOC_MinSOC_MinSOC].&amp;quot; %&amp;quot;):&amp;quot;wartet&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_DayBefore])).STY(&amp;quot;gestern&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_DayBefore],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_Actual])).STY(&amp;quot;geplant&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_Actual],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMiddayControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMiddayControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Limits&amp;lt;dd&amp;gt;Inverter_Max_Power / Laden nicht vor / Start /Stop&amp;lt;br&amp;gt;MaxSOC morgens / Power morgens / Power mittags&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMidday_Inverter_Max_Power],&amp;quot;selectnumbers,1000,250,15000,0,lin&amp;quot;).&amp;quot;W&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:SpeicherMidday_MaxSOC],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; | widget([$SELF:SpeicherMidday_NotBefore],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_morning],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_start],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_midday],&amp;quot;selectnumbers,0,100,4700,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_stop],&amp;quot;time&amp;quot;).([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0)?&amp;quot;dynamisch&amp;quot;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MinSOC Steuerung&amp;lt;dd&amp;gt;fc1_Limit / Winter | Sommer /aktuell&amp;lt;/dd&amp;gt;&amp;quot;|\&lt;br /&gt;
 FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMinSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;).widget([$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;).&amp;quot;wh&amp;quot; |\&lt;br /&gt;
 widget([$SELF:SpeicherMinSOC_Winter],&amp;quot;selectnumbers,10,1,30,0,lin&amp;quot;).widget([$SELF:SpeicherMinSOC_Sommer],&amp;quot;selectnumbers,5,1,10,0,lin&amp;quot;).&amp;quot;%&amp;quot; |&amp;quot;&amp;quot;|[WR_1_API:Battery_InternControl_MinSoc].&amp;quot; %&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherCmdRepeatActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherCmdRepeatRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-11 17:23:40 SpeicherDcPowerAbs 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:13 SpeicherEntladung Automatik&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherExternTrigger none&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherMaxSOCControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOCControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOC_Actual 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMaxSOC_DayBefore 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_MinSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_Time NULL&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:38:43 SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:27 SpeicherMiddayControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMiddayControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:12 SpeicherMidday_Inverter_Max_Power 9000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-08 11:21:31 SpeicherMidday_MaxChargePowerAbs_midday 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:31 SpeicherMidday_MaxChargePowerAbs_morning 450&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:28 SpeicherMidday_MaxSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-03 09:21:27 SpeicherMidday_NotBefore 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 18:45:27 SpeicherMinSOC_Sommer 5&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:54 SpeicherMinSOC_Winter 20&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-15 08:04:40 SpeicherMinSOC_fc1_Limit 16000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:05 SpeicherTrigger entladen&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 16:10:24 SpeicherZeitEnde 19:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:41:25 SpeicherZeitStart 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 WB_1_smart_laden_before ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1 ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;&#039;&#039;&#039;disable 1&#039;&#039;&#039;&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_0_KSEM ModbusAttr 1 60 192.168.178.xyz:502 TCP&lt;br /&gt;
attr WR_0_KSEM DbLogExclude .*&lt;br /&gt;
attr WR_0_KSEM DbLogInclude Active_energy.*&lt;br /&gt;
attr WR_0_KSEM alias WR_0_KSEM&lt;br /&gt;
attr WR_0_KSEM comment Version 2021.04.07 12:00\&lt;br /&gt;
Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\&lt;br /&gt;
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\&lt;br /&gt;
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\&lt;br /&gt;
\&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\&lt;br /&gt;
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\&lt;br /&gt;
\&lt;br /&gt;
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
attr WR_0_KSEM dev-h-defPoll 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr WR_0_KSEM disable 0&lt;br /&gt;
attr WR_0_KSEM event-on-change-reading Active_energy.*,M_AC_Current_.*&lt;br /&gt;
attr WR_0_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr WR_0_KSEM icon measure_power&lt;br /&gt;
attr WR_0_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr WR_0_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr WR_0_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr WR_0_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40075-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr WR_0_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr WR_0_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr WR_0_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40084-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40086-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40087-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr WR_0_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr WR_0_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr WR_0_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40091-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40096-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr WR_0_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr WR_0_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr WR_0_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40101-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr WR_0_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr WR_0_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr WR_0_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr WR_0_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr WR_0_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h512-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr WR_0_KSEM obj-h512-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h516-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr WR_0_KSEM obj-h516-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr WR_0_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr WR_0_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr WR_0_KSEM obj-h8196-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr WR_0_KSEM obj-h8212-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr WR_0_KSEM obj-h8228-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr WR_0_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr WR_0_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_0_KSEM sortby 140&lt;br /&gt;
attr WR_0_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr WR_0_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===BYD HV Speicher (mit HTTPMOD)===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort wird mit KeyValue() (siehe oben) verwaltet.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Der BYD HV Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
 - Die erste Abfrage führt das Login durch&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num *&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
&lt;br /&gt;
======KeyValue() speichern======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline aufgerufen werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition WR_1_Speicher_1 (BYD HV)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1 HTTPMOD http://%IP-WR_1_Speicher_1%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr WR_1_Speicher_1 DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1 DbLogInclude BatteryInformation_TotalVoltage,BatteryInformation_SOC,BatteryInformation_SOC,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 authRetries 1&lt;br /&gt;
attr WR_1_Speicher_1 comment Version 2021.04.07 12:00&lt;br /&gt;
attr WR_1_Speicher_1 dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_Speicher_1 enableControlSet 0&lt;br /&gt;
attr WR_1_Speicher_1 enableCookies 1&lt;br /&gt;
attr WR_1_Speicher_1 event-on-change-reading auth_.*,Battery.*_.*,Device.*_.*,Installation.*_.*,Array_.*,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 event-on-update-reading Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr WR_1_Speicher_1 get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr WR_1_Speicher_1 get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr WR_1_Speicher_1 get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr WR_1_Speicher_1 get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr WR_1_Speicher_1 get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr WR_1_Speicher_1 get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr WR_1_Speicher_1 get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr WR_1_Speicher_1 get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr WR_1_Speicher_1 get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr WR_1_Speicher_1 get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr WR_1_Speicher_1 get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr WR_1_Speicher_1 get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr WR_1_Speicher_1 get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr WR_1_Speicher_1 get01-16Name Array_Main_Current&lt;br /&gt;
attr WR_1_Speicher_1 get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr WR_1_Speicher_1 get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr WR_1_Speicher_1 get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr WR_1_Speicher_1 get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr WR_1_Speicher_1 get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr WR_1_Speicher_1 get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr WR_1_Speicher_1 get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr WR_1_Speicher_1 get01-22Name Array_Main_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr WR_1_Speicher_1 get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-73Name Array_Main_Power&lt;br /&gt;
attr WR_1_Speicher_1 get01-80Name Array_Series_Battery&lt;br /&gt;
attr WR_1_Speicher_1 get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr WR_1_Speicher_1 get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get01Name RunData&lt;br /&gt;
attr WR_1_Speicher_1 get01RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get02Name StatisticInformation&lt;br /&gt;
attr WR_1_Speicher_1 get02RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get02URL http://%IP-WR_1_Speicher_1%/asp/StatisticInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr WR_1_Speicher_1 get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr WR_1_Speicher_1 get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03Name DeviceInformation&lt;br /&gt;
attr WR_1_Speicher_1 get03RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get03URL http://%IP-WR_1_Speicher_1%/asp/DeviceInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-37Name BatteryInformation_Power&lt;br /&gt;
attr WR_1_Speicher_1 get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr WR_1_Speicher_1 get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-9Name BatteryInformation_Current&lt;br /&gt;
attr WR_1_Speicher_1 get04DeleteIfUnmatched 1&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get04Name BatteryInformation&lt;br /&gt;
attr WR_1_Speicher_1 get04RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr WR_1_Speicher_1 get04URL http://%IP-WR_1_Speicher_1%/asp/Home.asp&lt;br /&gt;
attr WR_1_Speicher_1 get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr WR_1_Speicher_1 get05Name InstallationConfig&lt;br /&gt;
attr WR_1_Speicher_1 get05RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get05URL http://%IP-WR_1_Speicher_1%/asp/UserInfo.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Data ArrayNum=1&amp;amp;SeriesBatteryNum=4&lt;br /&gt;
attr WR_1_Speicher_1 get10Header01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 get10Header02 Referer: http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Header03 Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
attr WR_1_Speicher_1 get10Header04 Accept: text/html,application/xhtml+xml,application/xml&lt;br /&gt;
attr WR_1_Speicher_1 get10Name Test_Array&lt;br /&gt;
attr WR_1_Speicher_1 get10URL http://%IP-WR_1_Speicher_1%/goform/SetRunData&lt;br /&gt;
attr WR_1_Speicher_1 getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1 handleRedirects 1&lt;br /&gt;
attr WR_1_Speicher_1 httpVersion 1.1&lt;br /&gt;
attr WR_1_Speicher_1 icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1 reAuthRegex Unauthorized&lt;br /&gt;
attr WR_1_Speicher_1 reading01Name auth_qop&lt;br /&gt;
attr WR_1_Speicher_1 reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Name auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Name auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Name auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Regex %IP-WR_1_Speicher_1%&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Value ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1_Speicher_1&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Regex %auth_realm%&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Value auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Regex %auth_nonce%&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Value auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Regex %auth_opaque%&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Value auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Regex %auth_response%&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Value {my $NAME=&amp;quot;WR_1_Speicher_1&amp;quot;;;my $pw=KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;);; $pw =~ &#039;&amp;quot;&#039;.s/@/\\@/g.&#039;&amp;quot;&#039;;; md5_hex(md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.$pw).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:00000001:d789ea5b7e9a2377:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;));;}&lt;br /&gt;
attr WR_1_Speicher_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1 showBody 0&lt;br /&gt;
attr WR_1_Speicher_1 showError 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid01ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sid02Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid02ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid02URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sortby 121&lt;br /&gt;
attr WR_1_Speicher_1 stateFormat {sprintf(&amp;quot;Total_Charge_Energy: %.0f kWh&amp;lt;br&amp;gt;Total_Efficiency: %.1f %% Battery_EM_State: %s&amp;quot;, ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Efficiency&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;Battery_EM_State&amp;quot;,&amp;quot;&amp;quot;))}&lt;br /&gt;
attr WR_1_Speicher_1 userReadings Statistic_SpecificInformation_00_Date:Statistic_SpecificInformation_05_EndTime.* { CommandDeleteReading(undef, $NAME.&amp;quot; .*-.*&amp;quot;);;;; localtime()},\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Difference_Charge_Energy:Statistic_GeneralInformation_Total_Charge_Energy.*  {ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Efficiency:Statistic_GeneralInformation_Total_Charge_Energy.*  {round(((ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)+((ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Act_state_of_charge&amp;quot;,0)/100)*11)) / ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0))*100 , 2)}&lt;br /&gt;
attr WR_1_Speicher_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1                    BYD HV     HTTPMOD   LAN/WLAN               Speicher Details, auch über einzelne Zellen. Das kann man nur für den alten BYD HV verwenden.&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Verwendet von Plenticore zur Steuerung des Speichers&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
PV_Schedule                                   DOIF                             Startet regelmäßige Aktionen&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Das ist veraltet, da die KI_Prognose nun verwendet werden sollte.&lt;br /&gt;
   2 Stündlich von 07:00 bis 20:00&lt;br /&gt;
   2.1 WR_1_config module_1_covered                                              Schnee auf den Modulen (noch in der Entwicklungsphase)&lt;br /&gt;
   2.2 Solar_forecast() für fc0                                                  Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 zweimal am Tag&lt;br /&gt;
   3.1 Solar_forecast() für fc1                                                  Aktualisieren der fc1 Prognose&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
   4 alle 5 Minuten&lt;br /&gt;
   4.1 WR_2_API 04_auth_me                                                       Aktualisieren der Bilanz (es wird ein Event erzeugt)&lt;br /&gt;
   4.2 WR_1_API 04_auth_me                                                       Der Master Wechselrichter kommt zum Schluss, damit die SW_* readings auch von anderen&lt;br /&gt;
                                                                                 Wechselrichtern die richtigen Werte haben.&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Dies ist jetzt im WR_ctl Device enthalten&lt;br /&gt;
WR_*_config                                   DUMMY                            Konfiguration für Strings,Ausrichtung,Nennleistung,IP-Adressen,Forecast&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC               begrenzt dann morgens den MaxSOC&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday     und den MaxChargePowerAbs&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning    für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_1:Solar_middayhigh_fc0_start &amp;lt;&amp;gt; WR_1:Solar_middayhigh_fc0_stop      Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_1:Solar_middayhigh_fc0_stop                         Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====SVG====&lt;br /&gt;
In eventuellen SVGs die Device und reading Namen korrigieren&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== AW Definition PV_Schedule (DOIF)===&lt;br /&gt;
Aufgrund der Komplexität wurde die Speichersteuerung aus diesem Device entfernt und im Device PV_1_Speicher_1_ExternControl ausgelagert.&lt;br /&gt;
Weitere Neuerungen sind die Bereitstellung eines Schnee Faktors pro String für die Solar_forecast() Funktion, was aber bitte als Versuch anzusehen ist.&lt;br /&gt;
Für den Vergleich mit dem Solar_Foracast Modul wird der Forecast zwei mal aufgerufen und einmal davon ins DWD_Forecast_Test geschrieben.&lt;br /&gt;
Diese Beispiele können natürlich einfach herausgelöscht werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
\&lt;br /&gt;
   (get WR_2_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
   (get WR_1_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 5 und 21 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([05:00-21:00] and [:00])\&lt;br /&gt;
   ## Erste Versuche mit Schnee, wenn zuwenig Strom in den Modulen fließt wird ein Faktor von 0.1 gesetzt\&lt;br /&gt;
   ## WR_1_config forecast_factor_autocorrection muss auf 1 gesetzt sein, damit das berücksichtigt wird\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt;  8 &amp;amp;&amp;amp; $hour &amp;lt; 12)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_1_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_2_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 12 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_3_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_4_covered &amp;quot;.$y)})\&lt;br /&gt;
\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   ## Bei Schnee wurde der module_*_covered Faktor bereits am Vortag gesetzt.\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 regelmäßig die Bilanz aktualisieren, alle 5 Minuten außer um :00\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00])\&lt;br /&gt;
\&lt;br /&gt;
  (get WR_2_API 04_auth_me)\&lt;br /&gt;
  (get WR_1_API 04_auth_me)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])   ## 6172\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])         ## 4727\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5707\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 4717\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5241\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 3517\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState WR Status|Forecast 0|Forecast 1|Bilanz refresh&lt;br /&gt;
attr PV_Schedule comment Version 2021.04.19 12:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0,3:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4&lt;br /&gt;
attr PV_Schedule webCmdLabel Statistic :Forecast_0 :Forecast_1 :Bilanz :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc.*_.*_Rad1h,fc.*_.*_TTT,fc.*_.*_FF,fc.*_.*_Neff,fc.*_.*_R101,fc.*_.*_RRS1c,fc.*_.*_DD,fc.*_.*_N,fc.*_.*_VV,fc.*_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2022.08.20 12:00\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
FF      : Windspeed\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc.*_.*_[Rad1h|TTT|FF|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,FF,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz,fc.*_.*&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro event-on-update-reading ObsDate.*,fc.*_.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
attr Astro userReadings fc0_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
\&lt;br /&gt;
fc1_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))}&lt;br /&gt;
attr Astro verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
CREATE DEFINER=`fhemuser`@`%` PROCEDURE `dwd_load`(IN var_date DATE, IN display char(10))&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;br /&gt;
SET @date:= var_date;&lt;br /&gt;
-- die alte Tabelle löschen&lt;br /&gt;
DROP TABLE IF EXISTS dwdfull;&lt;br /&gt;
&lt;br /&gt;
-- eine neue Tabelle anlegen&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `dwdfull` (&lt;br /&gt;
  `TIMESTAMP` datetime NOT NULL,&lt;br /&gt;
  `year`   int NOT NULL,&lt;br /&gt;
  `month`  int NOT NULL,&lt;br /&gt;
  `day`    int NOT NULL,&lt;br /&gt;
  `hour`   int NOT NULL,&lt;br /&gt;
  `TTT`    float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `DD`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `VV`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `N`      float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Neff`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `R101`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `RRS1c`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunD1`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Rad1h`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAz`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAlt` float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `yield`  float  DEFAULT 0,&lt;br /&gt;
  `yield_max`  float  DEFAULT 0,&lt;br /&gt;
  `forecast`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  PRIMARY KEY (`TIMESTAMP`),&lt;br /&gt;
  INDEX (`TIMESTAMP`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=&#039;DWD Forecast&#039;;&lt;br /&gt;
&lt;br /&gt;
-- als erstes die Grundlegenden Daten mit Zeitstempeln erzeugen&lt;br /&gt;
-- Rad1h wird als erstes eingetragen&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc0 Rad1h ältere Werte eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
	 	       )&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc1 Rad1h Werte von morgen eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Mit update alle weiteren Spalten füllen&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAz&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t2  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t2.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAz&lt;br /&gt;
  SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAlt&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t6 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t6.VV&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t5.VV&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t7 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t7.DD&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t5.DD&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t8 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t8.TTT&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t5.TTT&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t9 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t9.R101&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t5.R101&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t10 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t10.N&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t5.N&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t11 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t11.RRS1c&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t5.RRS1c&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield from Plenticore with Accu&lt;br /&gt;
   -- start left join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    left JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end left join&lt;br /&gt;
   &lt;br /&gt;
   UNION  -- for left and right join&lt;br /&gt;
&lt;br /&gt;
   -- start right join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    right JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end right join&lt;br /&gt;
   &lt;br /&gt;
   -- UNION end&lt;br /&gt;
   &lt;br /&gt;
  ) t12 USING(TIMESTAMP)&lt;br /&gt;
SET tt.yield = t12.yield&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Ermittle Ertrags Maximum der letzten 30 Tage um die Prognose zu limitieren&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield_max&lt;br /&gt;
      SELECT hour,&lt;br /&gt;
             cast(max(yield) AS DECIMAL(6)) AS yield_max&lt;br /&gt;
      FROM dwdfull&lt;br /&gt;
      WHERE TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
      GROUP BY hour&lt;br /&gt;
   ) t2  USING(hour)&lt;br /&gt;
SET tt.yield_max = t2.yield_max&lt;br /&gt;
WHERE TIMESTAMP &amp;gt; @date&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
IF display = &#039;show&#039; THEN &lt;br /&gt;
  select * from dwdfull LIMIT 3000;&lt;br /&gt;
ELSE&lt;br /&gt;
  select now();&lt;br /&gt;
END IF&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose (nicht mehr aktuell)==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
====Wetter Forecast Grundlagen (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der &lt;br /&gt;
    Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deutscher Wetter Dienst (DWD) (nicht mehr aktuell)===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
====RAW Definition DWD_Forecast (nicht mehr aktuell)====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wurden einige extra Werte vom DWD abgefragt, die für das Solar_Forecast Modul verwendet werden. Dieses Modul ist noch in der experimental Phase (2021.02.23) und liefert noch nicht gleichwertige Ergebnisse. Ein Test zum vergleichen kann aber nicht schaden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc0_.*_Rad1h,fc0_.*_TTT,fc0_.*_Neff,fc0_.*_R101,fc0_.*_RRS1c,fc0_.*_DD,fc0_.*_N,fc0_.*_VV,fc0_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2023.01.05 12:40\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc0_.*_[Rad1h|TTT|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===99_myUtils.pm Funktionen===&lt;br /&gt;
====Solar_forecast() (nicht mehr aktuell)====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen, muss ein Dummy WR_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Letzte Neuerungen:&lt;br /&gt;
- IM WR_1_config kann man verbose auf &amp;gt;3 setzen und bekommt dann Log Meldungen&lt;br /&gt;
- Es wird eine Autokorrektur unterstützt. Aktivierung durch &amp;quot;setreading WR_1_config forecast_factor_autocorrection 1&amp;quot;&lt;br /&gt;
  Für die Datenbank Anbindung wird ein DbRep Device LogDBRep_PV_Forecast_SQL verwendet. Die RAW definition kommt gleich im Anschluss.&lt;br /&gt;
- Das SQL für die Berechnung des Faktors der Autokorrektur Verwendet Konfigurationsvariablen aus den DbRep Device.&lt;br /&gt;
- Bei der Autokorrektur wird auch eine Bedeckung von Schnee (Strom im String &amp;lt; 1A) berücksichtigt. (das ist noch in der Entwicklung)&lt;br /&gt;
  Dieser Faktor wird im PV_Schedule Device erzeugt und dann im &amp;quot;WR_1_config module_*_covered&amp;quot; für jeden String eingetragen.&lt;br /&gt;
  Das muss jeder individuell für seine Anlage anpassen!&lt;br /&gt;
- Für die 70% Regelung wird nun auch ein Middayhigh Trigger ermittelt und die jeweilige Start/Stop Zeit. Dies steht dann im WR_1 Device bei den Solar_* readings&lt;br /&gt;
- Es besteht auch die Möglichkeit die Solar_forecast() Funktion ohne Datenbank zu verwenden, dann ist bei den Parametern &amp;quot;none&amp;quot; zu übergeben und&lt;br /&gt;
  es muss auch die Autokorrektur abgeschaltet sein.&lt;br /&gt;
- Anstelle des Wechselrichter Devices kann nun auch ein beliebiges anderes Device angegeben werden, in das dann der Forecast geschrieben wird.&lt;br /&gt;
  Auch hier kann dann keine Autokorrektur verwendet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.06.14 15:20&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;        # Mit dieser Datenbank wird gearbeitet&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zur Kommunikation mit der LogDB verwendet und muss entsprechend konfiguriert sein&lt;br /&gt;
     my $logdevice   = &amp;quot; &amp;quot;   ;        # Das ist der Wechselrichter, oder ein anderes Device, in das die Prognose geschrieben wird&lt;br /&gt;
        $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;    # Der reading Name wird um 0 oder 1 verlängert&lt;br /&gt;
&lt;br /&gt;
     # Welcher Verbose Level ist gesetzt?&lt;br /&gt;
     my $verbose = AttrVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Gibt es einen festen Korrekturfaktor für jede Stunde?&lt;br /&gt;
     my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
     # Soll eine Autokorrektur gemacht werden? 0 = Nein 1 = Ja&lt;br /&gt;
     my $autocorrection          = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor_autocorrection&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Beim DWD wird der Wert für die Stunde erst am Ende der Stunde eingetragen&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     # Hier werden die Variablen vorbelegt&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry1h,$logentry4h,$logentryrest,$logentry,$i) = (0) x 9 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($module_covered,$Solar_Correction_Faktor_auto,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 6 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 06:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $logdbrep ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
       # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
       CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Setzen der Tageszähler und Merker&lt;br /&gt;
     $logentry            = 0 ;   # Summiert den Solar_Calculation Wert für den ganzen Tag&lt;br /&gt;
     $logentry4h          = 0 ;   # Summierung für die nächsten vier Stunden&lt;br /&gt;
     $logentryrest        = 0 ;   # Summierung für den Rest des Tages&lt;br /&gt;
&lt;br /&gt;
     my $middayhigh           = 0 ; # Ein Merker, ob das Tagesmaximum überschritten wird&lt;br /&gt;
     my $middayhigh_start     = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_stop      = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_tmp       = 0;&lt;br /&gt;
     my $middayhigh_start_tmp = 0;&lt;br /&gt;
     my $middayhigh_stop_tmp  = 0;&lt;br /&gt;
&lt;br /&gt;
     my $Inverter_Max_Power = ReadingsVal($logdevice.&amp;quot;_Speicher_1_ExternControl&amp;quot;,&amp;quot;SpeicherMidday_Inverter_Max_Power&amp;quot;,&amp;quot;unused&amp;quot;);  # Überschreiben des middayhigh&lt;br /&gt;
     if ($Inverter_Max_Power eq &amp;quot;unused&amp;quot;) {&lt;br /&gt;
       $Inverter_Max_Power = ReadingsVal($logdevice,&amp;quot;Inverter_Max_Power&amp;quot;,0) +500 ;      # Hier wird ein Durchschnittsverbrauch des Hauses aufaddiert&lt;br /&gt;
     } else {&lt;br /&gt;
       if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power manuell gesetzt&amp;quot; } ;&lt;br /&gt;
     };&lt;br /&gt;
     if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power auf &amp;quot;.$Inverter_Max_Power.&amp;quot; gesetzt&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
     # Es werden Stundenwerte von 06:00 bis 21:00 Uhr berechnet&lt;br /&gt;
     for ($i = 6; $i &amp;lt;= 21; $i++) {&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0 and $i == 6) {&lt;br /&gt;
         # Neuberechnung der stündlichen Autokorrektur Faktoren in der Datenbank. Das DbRep Device LogDBRep_PV_Forecast_SQL muss vorhanden sein.&lt;br /&gt;
         # Achtung, beim SQL muss &#039;@&#039; mit &#039;\@&#039; maskiert werden.&lt;br /&gt;
         CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking &amp;quot;.sprintf(&amp;quot;&lt;br /&gt;
               INSERT INTO history&lt;br /&gt;
                 (TIMESTAMP,DEVICE,READING,VALUE)&lt;br /&gt;
                  SELECT&lt;br /&gt;
                    TIMESTAMP,DEVICE,READING,VALUE&lt;br /&gt;
                  FROM (&lt;br /&gt;
                    SELECT&lt;br /&gt;
                      DATE_ADD(CURDATE(),INTERVAL t2.HOUR HOUR) AS TIMESTAMP,&lt;br /&gt;
                      t2.DEVICE,&lt;br /&gt;
                      \@readingname                             AS READING,&lt;br /&gt;
                      cast(if(avg(t2.FACTOR) &amp;gt; 1.6, 1.6,&lt;br /&gt;
                              avg(t2.FACTOR) ) AS DECIMAL(2,1)) AS VALUE&lt;br /&gt;
                    FROM (&lt;br /&gt;
                      SELECT * FROM (&lt;br /&gt;
                        SELECT&lt;br /&gt;
                          t1.TIMESTAMP,&lt;br /&gt;
                          t1.HOUR,&lt;br /&gt;
                          t1.DEVICE,&lt;br /&gt;
                          t1.READING,&lt;br /&gt;
                          t1.VALUE,&lt;br /&gt;
                          if(\@diff = 0,0, \@temp:=cast((t1.VALUE-\@diff) AS DECIMAL(8,2)))                                    AS DIFF,&lt;br /&gt;
                          if(((t1.VALUE+(-1*\@temp))*\@corr)=0,0, cast((t1.VALUE/(t1.VALUE+(-1*\@temp))*\@corr) AS DECIMAL(8,1))) AS FACTOR,&lt;br /&gt;
                          \@diff:=t1.VALUE                                                                                        AS curr_V&lt;br /&gt;
                        FROM (&lt;br /&gt;
                          SELECT&lt;br /&gt;
                            h.TIMESTAMP,&lt;br /&gt;
                            date(h.TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(h.TIMESTAMP) AS HOUR,&lt;br /&gt;
                            h.DEVICE,&lt;br /&gt;
                            h.READING,&lt;br /&gt;
                            h.VALUE&lt;br /&gt;
                          FROM history AS h&lt;br /&gt;
                          WHERE h.DEVICE    =  \@device&lt;br /&gt;
                            AND (h.READING  =  \@reading1 OR h.READING = \@reading2)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;gt;= DATE_SUB(DATE(now()),INTERVAL \@days DAY)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;lt;= CURDATE()&lt;br /&gt;
                            AND MINUTE(h.TIMESTAMP) = 0&lt;br /&gt;
                            AND h.VALUE &amp;gt;= 50&lt;br /&gt;
                          GROUP BY DATE,HOUR,h.READING,h.DEVICE,h.TIMESTAMP&lt;br /&gt;
                         )t1&lt;br /&gt;
                       )tx&lt;br /&gt;
                        WHERE READING != \@reading2&lt;br /&gt;
                          AND HOUR &amp;gt; 6&lt;br /&gt;
                     )t2&lt;br /&gt;
                      GROUP BY t2.HOUR,t2.DEVICE&lt;br /&gt;
                   )t3&lt;br /&gt;
                    WHERE&lt;br /&gt;
                      t3.VALUE != 0&lt;br /&gt;
                    ORDER BY TIMESTAMP&lt;br /&gt;
                    ON DUPLICATE KEY UPDATE&lt;br /&gt;
                      VALUE=t3.VALUE;&lt;br /&gt;
           &amp;quot;) # Ende sprintf()&lt;br /&gt;
         );   # Ende CommandGet()&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
       $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
       if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
         $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
&lt;br /&gt;
         $Solar_Rain = 0;&lt;br /&gt;
         for (my $r600 = $i+5; $r600 &amp;gt;= $i; $r600--) {&lt;br /&gt;
           $Solar_Rain        += ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($r600+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
         $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
         $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
         $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
         if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation.&amp;quot; W &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0).&amp;quot; J&amp;quot; } ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($cloudk ne 0) {&lt;br /&gt;
         $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
         $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($raink ne 0) {&lt;br /&gt;
         $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($tempk ne 0) {&lt;br /&gt;
         $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0) {&lt;br /&gt;
         $Solar_Correction_Faktor_auto = CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking SELECT VALUE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;Solar_Correction_Faktor_auto&#039; AND TIMESTAMP=&#039;&amp;quot;.sprintf(&amp;quot;%4d-%02d-%02d %02d:00:00&amp;quot;,$year,$mon,$mday,$i).&amp;quot;&#039;;&amp;quot;) ;&lt;br /&gt;
         if($Solar_Correction_Faktor_auto eq &amp;quot;&amp;quot;) { $Solar_Correction_Faktor_auto = 1; };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $logentry1h = 0 ;   # Summierung für eine Stunde zurücksetzen&lt;br /&gt;
&lt;br /&gt;
       # Es werden 5 Modul Ausrichtungen durchlaufen, der Name der Ausrichtung befindet sich z.B. in WR_1_config&lt;br /&gt;
       for(my $j=1;$j&amp;lt;=5;$j++){&lt;br /&gt;
         # lesen der Modul Anzahl&lt;br /&gt;
         $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
         if ($module_count[$j] ne 0) {&lt;br /&gt;
           # Für diese Ausrichtung sind Module Installiert&lt;br /&gt;
&lt;br /&gt;
           # Berechnung des Korrekturfaktors für die Modul Ausrichtung&lt;br /&gt;
           $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;factor/plain/direction       : &amp;quot;.$Solar_Plain.&amp;quot; &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) };&lt;br /&gt;
           # Berechnung der Modul Nennleistung für diese Ausrichtung&lt;br /&gt;
           $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
           # Anwendung der Korrekturfaktoren&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp   * $Solar_Correction_Cloud * $Solar_Correction_Rain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Faktor ;&lt;br /&gt;
&lt;br /&gt;
           if ($autocorrection ne 0) {&lt;br /&gt;
             # Nachsehen, ob dieser String mit Schnee bedeckt ist&lt;br /&gt;
             $module_covered = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_covered&amp;quot;,1) ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $Solar_Correction_Faktor_auto ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $module_covered ;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot;_covered             : &amp;quot;.$module_covered };&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Runden auf volle Watt Werte&lt;br /&gt;
           $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot; estimation          : &amp;quot;.$Solar_[$j] };&lt;br /&gt;
&lt;br /&gt;
           # Aufsummieren aller konfigurierter Ausrichtungen&lt;br /&gt;
           $logentry1h += $Solar_[$j] ; # Summe für eine Stunde (wird mit jedem lauf von $i wieder auf 0 gesetzt)&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe der nächsten 4 h gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour and $i &amp;lt;= $hour+3) {&lt;br /&gt;
             $logentry4h += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe für den Resttag gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour) {&lt;br /&gt;
             $logentryrest += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           $logentry += $Solar_[$j] ; # Summe für den ganzen Tag&lt;br /&gt;
&lt;br /&gt;
           # Den Forecast Wert für die aktuelle Stunde in das Wechselrichter Device schreiben&lt;br /&gt;
           if ($fc == 0 and $hour == $i) {&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;                   : &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; };&lt;br /&gt;
             CommandSetReading(undef, $logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j]) ;&lt;br /&gt;
           };&lt;br /&gt;
         };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Alle Forecast Werte für die jeweilige Stunde in die DbLog schreiben (Es wird der Cache verwendet)&lt;br /&gt;
&lt;br /&gt;
       if ( $logdb ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
         CommandSet(undef, $logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry1h.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry1h.&amp;quot;|&amp;quot;) ;&lt;br /&gt;
&lt;br /&gt;
         if ( $middayhigh == 0 and $logentry1h &amp;gt; $Inverter_Max_Power ) {&lt;br /&gt;
           $middayhigh           = 1;&lt;br /&gt;
           $middayhigh_start_tmp = $i-1;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;lt; $Inverter_Max_Power and $middayhigh_stop_tmp == 0 )  {&lt;br /&gt;
           $middayhigh_stop_tmp = $i;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;gt; $Inverter_Max_Power and $middayhigh_stop ne &amp;quot;00:00&amp;quot; )  {&lt;br /&gt;
           $middayhigh_stop_tmp = 0;                                # da war ein kurzer Einbruch, es sollte noch länger sein.&lt;br /&gt;
         };&lt;br /&gt;
         if ($middayhigh == 1 and&lt;br /&gt;
             $middayhigh_stop_tmp != 0 and&lt;br /&gt;
             $middayhigh_stop_tmp == $i ) {                                    # das Ende des Middayhigh wurde gefunden&lt;br /&gt;
&lt;br /&gt;
           $middayhigh_tmp = $middayhigh_stop_tmp - $middayhigh_start_tmp;&lt;br /&gt;
           if ( $middayhigh_tmp &amp;gt; 4 )  {                                       # das Middayhigh wird zu lang&lt;br /&gt;
             if ($verbose &amp;gt;= 3 ) {                                             # die bisherigen Zeiten ausgeben&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp) ;&lt;br /&gt;
             }&lt;br /&gt;
             $middayhigh_tmp       = round(($middayhigh_tmp/4)-0.2 ,0);        # die Rundung der Zeit zum Abziehen etwas verschieben&lt;br /&gt;
             $middayhigh_start_tmp = $middayhigh_start_tmp + $middayhigh_tmp;  # es wird um ganze Stunden verkürzt&lt;br /&gt;
             $middayhigh_stop_tmp  = $middayhigh_stop_tmp  - $middayhigh_tmp;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) {                                              # melde die Verkürzung&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;         : verkürzt um &amp;quot;.($middayhigh_tmp *2).&amp;quot; Stunden&amp;quot;;&lt;br /&gt;
             }&lt;br /&gt;
           };&lt;br /&gt;
           $middayhigh_start = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
           $middayhigh_stop  = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp);&lt;br /&gt;
           if ($verbose &amp;gt;= 3) {                                                # gib die finalen Zeiten aus&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.$middayhigh_start;&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.$middayhigh_stop ;&lt;br /&gt;
           }&lt;br /&gt;
         };&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ; # setz die Zeiten im Device&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Sobald mindestens ein String configuriert ist sollen diese Werte, der aktuellen Stunde, in das Wechselrichter Device geschrieben werden&lt;br /&gt;
       if ($fc == 0 and $hour == $i and $module_count[1] ne 0) {&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry1h) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Auch die Solar_Calculation jeder einzelnen Stunde wird als reading in das Wechselrichter Device geschrieben&lt;br /&gt;
       CommandSetReading(undef, sprintf(&amp;quot;%s %s_%02d %d&amp;quot;,$logdevice,$reading,$i,$logentry1h)) ;&lt;br /&gt;
&lt;br /&gt;
       # Für die Fehlersuche kommen noch einige Informationen ins Log&lt;br /&gt;
       if ($verbose &amp;gt;= 3) {&lt;br /&gt;
         Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Cloud                  : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;cloudk                       : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Cloud       : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Rain                   : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;raink                        : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Rain        : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Temp                   : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;tempk                        : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Temp        : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor      : &amp;quot;.$Solar_Correction_Faktor ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor_auto : &amp;quot;.$Solar_Correction_Faktor_auto ;&lt;br /&gt;
         Log 3, &amp;quot;Forecast,Hour,Estimation 1h  : &amp;quot;.$fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$logentry1h ;&lt;br /&gt;
       };&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Die Summe der nächsten 4 Stunden in das Wechselrichter Device schreiben&lt;br /&gt;
     if ($fc == 0) {&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_4h &amp;quot;.$logentry4h) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_rest &amp;quot;.$logentryrest) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_day &amp;quot;.$logentry) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $middayhigh == 0 ) {    # Auf Defaults zurücksetzen&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.02.28 17:00&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    my $verbose     = AttrVal(&amp;quot;Astro&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = CommandGet(undef, &amp;quot;Astro text SunAz &amp;quot;.$time) ;&lt;br /&gt;
    my $elevation   = CommandGet(undef, &amp;quot;Astro text SunAlt &amp;quot;.$time) ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain time             : &amp;quot;.$time;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain azimuth          : &amp;quot;.$azimuth;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain elevation        : &amp;quot;.$elevation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain orientation      : &amp;quot;.$orientation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain angle            : &amp;quot;.$angle;&lt;br /&gt;
    };&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.1798) {&lt;br /&gt;
      if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_Forecast_SQL (nicht mehr aktuell)====&lt;br /&gt;
Dieses Device war vormals das LogDBRep_PV_Forecast_SQL , es wird jedoch nun mehrfach verwendet und wurde deshalb umbenannt. Das LogDBRep_PV_Forecast_SQL kann gelöscht werden.&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
Für die Solar_forecast() Funktion wurden hier SQL Variablen Definiert, die für die Autokorrektur verwendet werden:&lt;br /&gt;
- @days ist die Anzahl der Tage, über die ein stündlicher, durchschnitts Korrektur Faktor berechnet wird.&lt;br /&gt;
- @corr ermöglicht es diesen Faktor nochmals zu verändern &amp;lt;1 dämpft, &amp;gt;1 verstärkt&lt;br /&gt;
- @device ist der Plenticore Wechselrichter&lt;br /&gt;
- @reading1 ist die reale DC Leistung ohne die Batterie, hier wird &#039;&#039;&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;&#039;&#039; für die Schwarm Implementierung verwendet.&lt;br /&gt;
- @reading2 wird der Basisname der readings im WR_1 Device&lt;br /&gt;
- @readingname wird der reading Name des Korrekturfaktors.&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
Durch die Erweiterung zum Schwarm mit mehreren AC-Quellen wurde die Variable @reading1 verändert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_Forecast_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL allowDeletion 1&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL room System&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdVars SET @days:=3, @corr:=0.7, @diff:=0, @temp:=0, @device:=&#039;WR_1&#039;, @reading1:=&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;, @reading2:=&#039;Solar_Calculation_fc0&#039;, @readingname:=&#039;Solar_Correction_Faktor_auto&#039; ;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solar Forcast Tests (nicht mehr aktuell)===&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Astro Device Test====&lt;br /&gt;
Bei diesem Test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() Test (nicht mehr aktuell)====&lt;br /&gt;
Diese Funktion kann man folgendermaßen testen. Für Log Meldungen muss man im &#039;&#039;&#039;Astro Device verbose auf 3&#039;&#039;&#039; oder größer stellen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung, das Dach hätte demnach also Süd/West Lage.&lt;br /&gt;
&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann Folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:51:27.312 3: Solar_plain azimuth          : 210.6&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain elevation        : 0.49916224518291&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain orientation      : 0.185004188774085&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain angle            : 0.785395141022061&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain factor           : 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurückgeliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_forecast() Test (nicht mehr aktuell)====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
Bei gesetztem &amp;quot;&#039;&#039;&#039;attr Astro verbose 3&#039;&#039;&#039;&amp;quot; erscheinen hier ebenfalls die Astro Log Informationen.&lt;br /&gt;
Durch setzen von &amp;quot;&#039;&#039;&#039;attr WR_1_config verbose 3&#039;&#039;&#039;&amp;quot; bekommt man die Log Meldungen vom Sorar_forecast()&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&lt;br /&gt;
generische Verwendung ohne DbLog/DbRep: &#039;&#039;&#039;Das Astro Device muss &amp;quot;Astro&amp;quot; heißen und das DWD Device muss &amp;quot;DWD_Forecast&amp;quot; heißen!!&#039;&#039;&#039;&lt;br /&gt;
{Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;&amp;lt;beliebiges Device&amp;gt;&amp;quot;,&amp;quot;&amp;lt;prefix für die readings&amp;gt;_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,[0|1])}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann solche Blöcke, die man zusammenhängend betrachten sollte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power manuell gesetzt&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power auf 7000 gesetzt&lt;br /&gt;
2021.04.07 15:57:23.932 3: Solar_SolarRadiation         : 17 W 60.00 J        &amp;lt;&amp;lt;&amp;lt; vom DWD gelieferte Prognose in Watt und Joul&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain azimuth          : 80.2                &amp;lt;&amp;lt;&amp;lt; Astro Informationen&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain orientation      : -0.171041608489249&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain factor           : 0.001               &amp;lt;&amp;lt;&amp;lt; Die Funktion ist noch außerhalb des Gültigkeitsbereiches&lt;br /&gt;
2021.04.07 15:57:23.977 3: factor/plain/direction       : 0.001 40/-90     &lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1_covered             : 1                   &amp;lt;&amp;lt;&amp;lt; Ein Faktor für die Schneebedeckung&lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1 estimation          : 0                   &amp;lt;&amp;lt;&amp;lt; Die erwartete Leistung liegt bei 0 Watt&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:23.991 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2_covered             : 1&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain orientation      : -1.94183189053337&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.002 3: factor/plain/direction       : 0.001 40/0&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.013 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.020 3: Solar_SolarRadiation         : 17                  &amp;lt;&amp;lt;&amp;lt; Rad1h ist 70 Watt&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Cloud                  : 70                  &amp;lt;&amp;lt;&amp;lt; 70 % Abdeckung des Himmels durch Wolken&lt;br /&gt;
2021.04.07 15:57:24.021 3: cloudk                       : -0.45 0             &amp;lt;&amp;lt;&amp;lt; Werte der Korrekturfunktion für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Correction_Cloud       : 0.685               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Rain                   : 152&lt;br /&gt;
2021.04.07 15:57:24.022 3: raink                        : -0.2 0&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Correction_Rain        : 0.696               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Regen&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Temp                   : 10.7                &amp;lt;&amp;lt;&amp;lt; Erwartete Temperatur an den Modulen (Schätzung) &lt;br /&gt;
2021.04.07 15:57:24.023 3: tempk                        : -0.39 25&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Temp        : 1.056               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für die Modultemperatur&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor      : 1                   &amp;lt;&amp;lt;&amp;lt; Fester Korrekturfaktor aus WR_1_config &lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor_auto : 0.5                 &amp;lt;&amp;lt;&amp;lt; Korrekturfaktor aus der Datenbank Berechnung der letzten Tage &lt;br /&gt;
2021.04.07 15:57:24.024 3: Forecast,Hour,Estimation 1h  : 0 7 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Forecast Basiseinstellung (nicht mehr aktuell)===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät WR_1_config von einer Ost/Süd/West Anlage mitgeliefert (setstate). Es werden bis zu 5 Strings unterstützt.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auch &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät WR_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch zusätzliche Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Berücksichtigung von Temperatur, Bewölkung und Regen (nicht mehr aktuell)===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das Ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
Durch die Autokorrektur ist nun auch ein Schnee Faktor dazu gekommen. Dieser wird im PV_Schedule Device &amp;quot;berechnet&amp;quot; :-) und und in das PV_1_config geschrieben. Bei aktivierter Autokorrektur wird dieser dann berücksichtigt.&lt;br /&gt;
=====Temperatur (nicht mehr aktuell)=====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Wolken und Regen (nicht mehr aktuell)=====&lt;br /&gt;
Aus den DWD_Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken Einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
===wunderground===&lt;br /&gt;
Dieser Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das kann dann als aktueller Wert in den Diagrammen angezeigt werden und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mit einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
&lt;br /&gt;
===RAW Definition Wetter_&amp;lt;Wohnort&amp;gt;===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;JSON&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;builtIn&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;datasource&amp;quot;: &amp;quot;-- Grafana --&amp;quot;,&lt;br /&gt;
        &amp;quot;enable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;iconColor&amp;quot;: &amp;quot;rgba(0, 211, 255, 1)&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Annotations &amp;amp; Alerts&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;dashboard&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;editable&amp;quot;: true,&lt;br /&gt;
  &amp;quot;gnetId&amp;quot;: null,&lt;br /&gt;
  &amp;quot;graphTooltip&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;id&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;links&amp;quot;: [],&lt;br /&gt;
  &amp;quot;panels&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P value&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;: &amp;quot;rgb(90, 90, 90)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid value&amp;quot;: &amp;quot;rgb(250, 250, 250)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_AC_Active_P&amp;quot;: &amp;quot;dark-orange&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P&amp;quot;: &amp;quot;semi-dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 0&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: false,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:78&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:79&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:80&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 10,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:81&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:82&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:83&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 5,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS &#039;SW_Total_DC_P&#039;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_grid\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_grid&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_PV\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_PV&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_Battery\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_Battery&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Actual_Battery_charge_usable_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Actual_Battery_charge_usable_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_AC_Active_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_AC_Active_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;A&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Leistungsbezug&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Heizung&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Heizung value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Pool&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Waschmaschine&amp;quot;: &amp;quot;light-red&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 12&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hideEmpty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;hideZero&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: true,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;connected&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true,&lt;br /&gt;
          &amp;quot;steppedLine&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P_Max&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  abs(avg(value)) AS \&amp;quot;Heizung\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;StromZaehler_Heizung&#039; AND\n  READING = &#039;SMAEM1901401955_Saldo_Wirkleistung&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;StromZaehler_Heizung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SMAEM1901401955_Saldo_Wirkleistung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Pool\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly02&#039; AND\n  READING = &#039;Power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly02&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Waschmaschine\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly03&#039; AND\n  READING = &#039;power&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly03&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Brunnen\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Brunnen&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Shaun\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_1&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Shaun&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hauptverbraucher&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0&amp;quot;: &amp;quot;super-light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0 value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1 value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East value&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South value&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West&amp;quot;: &amp;quot;light-purple&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West value&amp;quot;: &amp;quot;super-light-purple&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 13,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 24&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: null,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc0\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc0&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc1\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc1&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc1&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_sumOfAllPVInputs\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_sumOfAllPVInputs&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_DC_Sum&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Solar_Calculation\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_Ost\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_Ost&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_Ost&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_Ost&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_Sued\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_Sued&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_Sued&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_Sued&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Forecast/Prognose&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;16000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;refresh&amp;quot;: &amp;quot;5m&amp;quot;,&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 27,&lt;br /&gt;
  &amp;quot;style&amp;quot;: &amp;quot;dark&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [],&lt;br /&gt;
  &amp;quot;templating&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: []&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;time&amp;quot;: {&lt;br /&gt;
    &amp;quot;from&amp;quot;: &amp;quot;now-1d/d&amp;quot;,&lt;br /&gt;
    &amp;quot;to&amp;quot;: &amp;quot;now-1d/d&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timepicker&amp;quot;: {&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;refresh_intervals&amp;quot;: [&lt;br /&gt;
      &amp;quot;5s&amp;quot;,&lt;br /&gt;
      &amp;quot;10s&amp;quot;,&lt;br /&gt;
      &amp;quot;30s&amp;quot;,&lt;br /&gt;
      &amp;quot;1m&amp;quot;,&lt;br /&gt;
      &amp;quot;5m&amp;quot;,&lt;br /&gt;
      &amp;quot;15m&amp;quot;,&lt;br /&gt;
      &amp;quot;30m&amp;quot;,&lt;br /&gt;
      &amp;quot;1h&amp;quot;,&lt;br /&gt;
      &amp;quot;2h&amp;quot;,&lt;br /&gt;
      &amp;quot;1d&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timezone&amp;quot;: &amp;quot;utc&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;PV_Anlage_1&amp;quot;,&lt;br /&gt;
  &amp;quot;uid&amp;quot;: &amp;quot;W-Y51Dmgk&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: 105&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit SVG==&lt;br /&gt;
Die Diagramme werden bei mir nicht mehr weiterentwickelt, da ich auf Grafana umgestiegen bin. Sie stehen hier nur noch als Beispiele für den Anfang.&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Total_PV_P_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_Battery::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB WR_1:SW_Actual_battery_charge_usable_P::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_Max::&lt;br /&gt;
#LogDB WR_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:max_month_SW_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_&amp;lt;Wohnort&amp;gt;_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB WR_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_sumOfAllPVInputs::&lt;br /&gt;
#LogDB WR_1:Solar_Calculation::&lt;br /&gt;
#LogDB WR_1:Solar_East::&lt;br /&gt;
#LogDB WR_1:Solar_South::&lt;br /&gt;
#LogDB WR_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power_(sumOfAllPVInputs)&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV_Perl (DOIF Modul) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 1                                   ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                     ## Die LWP ist aus\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]           ## Die maximale Laufzeit der LWP ist noch nicht erreicht\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## Das Maximum des PV-Modus ist noch nicht erreicht\&lt;br /&gt;
     and [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]   ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : LWP on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;LWP_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;PV_Modus_Ein_LWP();;set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;)&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : LWP on for manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : LWP off after manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]          ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : LWP off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; 100                              ## es soll noch eine Reserve bleiben\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : LWP off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;gt; 0                                  ## läuft eine Wartezeit\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 5                                  ## läuft die Wartezeit bald ab\&lt;br /&gt;
     and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot;\&lt;br /&gt;
      and [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe läuft&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer LWP &amp;quot;.get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;)};;\&lt;br /&gt;
    del_Exec(&amp;quot;LWP_Ein_timer&amp;quot;);;                                           ## Die LWP wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
## Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_1_LWP_Nachheizen_WW\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [[$SELF:TimeEnd]]                                               ## Am Ende der möglichen PV Steuerung\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt;= 48                             ## wenn das Wasser noch nicht im Sollbereich ist\&lt;br /&gt;
     and\&lt;br /&gt;
        (   [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]        ## Die maximale Laufzeit der LWP/Tag ist noch nicht erreicht\&lt;br /&gt;
         or [LWP_Counter:countsPerDay] eq 0)                             ## oder die LWP ist noch gar nicht gelaufen\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_LWP_Nachheizen_WW&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP on for water heating&amp;quot;};;\&lt;br /&gt;
                                                                         ## Es wird die Soll Temperatur um die Hysterese angehoben \&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget &amp;quot;.(ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,48)+4));;\&lt;br /&gt;
                                                                         ## Das zurücksetzen auf den Standard von 50° erfolgt generell beim Abschalten\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Hohe Priorität im Winter für die LWP\&lt;br /&gt;
## Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_2_LWP_Prioritaet_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [WR_1:SW_Total_PV_P_reserve] &amp;gt;= 2000                            ## es besteht jedoch noch eine Reserve und der\&lt;br /&gt;
     and [shelly02:power_0] &amp;gt; 800                                        ## Pool wird gerade aufgeheizt, was im Winter auch in der Nacht passiert\&lt;br /&gt;
     and [WR_1:Act_state_of_charge] &amp;gt; 60                                 ## Der Speicher sollte schon 60 % gefüllt sein\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## und die WW Temperatur noch unter 60°\&lt;br /&gt;
     and [$SELF:LWP_Priority] eq &amp;quot;frei&amp;quot;                                  ## Aber nur einmal am Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_LWP_Prioritaet_An&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_2 : LWP Priorität&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___LWP_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
        or [$SELF:LWP_Status] eq &amp;quot;manuell&amp;quot;\&lt;br /&gt;
       )\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimeMin]\&lt;br /&gt;
     and ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___LWP_Ende&amp;quot;                           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 05__ : LWP run finished&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Priorität für LWP wieder frei geben, damit einmal am Tag der PV-Modus verwendet werden kann\&lt;br /&gt;
##\&lt;br /&gt;
06___LWP_Prioritaet_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [23:55]\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;06___LWP_Prioritaet_Reset&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 06__ : LWP Priorität frei&amp;quot;};;\&lt;br /&gt;
     set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;frei&amp;quot;);;                                 ## Der PV-Modus darf wieder verwendet weden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## In der Überganszeit wird die Heizung kurz vor der PV-Zeit wieder ein geschaltet\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_1_Heizung_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeStartHeizung]]                                        ## Einschalten der Heizung, damit aus dem Puffer nachgeheizt wird 02:03\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_1_Heizung_An&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_1 : LWP Heizung Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHeating Auto&amp;quot;);;                  ## Die Heizungssteuerung erfolgt wieder Automatisch\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_2_Heizung_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeEndHeizung]]                                          ## Abschalten der Heizung, damit der Puffer für morgens Heizreserve hat\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_2_Heizung_Aus&amp;quot;                        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 07_2 : LWP Heizung aus&amp;quot;};;\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;Heizung opModeHeating Off&amp;quot;);;                     ## Die Heizung wird komplett abgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
   if (    [WR_1:Solar_Calculation_fc1_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] ## Auch morgen ist das Wetter schlecht\&lt;br /&gt;
       and [Heizung:averageAmbientTemperature] &amp;lt;= 5.6 ) {                ## Die Heizgrenze ist schon ziemlich tief\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungWinter]);;    ## Im Winter bis in die Morgenstunden den Accu sparen\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 07_2 : Parameter: &amp;quot;.[WR_1:Solar_Calculation_fc1_day].&amp;quot; &amp;lt; &amp;quot;.[WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit].&amp;quot; and &amp;quot;.[Heizung:averageAmbientTemperature].&amp;quot; &amp;lt;= 5.6&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungUebergang]);; ## Bei schönerem Wetter erst später Heizen\&lt;br /&gt;
     }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_2 : TimeStartHeizung switched to &amp;quot;.[$SELF:TimeStartHeizung]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 15°\&lt;br /&gt;
##\&lt;br /&gt;
07_3_Heizung_WZ_15_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_3_Heizung_WZ_15_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_3 : Heizung WZ 15 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 15&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 22°\&lt;br /&gt;
##\&lt;br /&gt;
07_4_Heizung_WZ_22_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_4_Heizung_WZ_22_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_4 : Heizung WZ 22 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 22&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung aus\&lt;br /&gt;
##\&lt;br /&gt;
07_5_Warmwasser_aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_5_Warmwasser_aus&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_5 : LWP Warmwasser aus&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Off&amp;quot;);;                  ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation inactive&amp;quot;);;                      ## Zirkulation ebenfalls abschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung auf Automatik\&lt;br /&gt;
##\&lt;br /&gt;
07_6_Warmwasser_an\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_6_Warmwasser_an&amp;quot;                      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_6 : LWP Warmwasser Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Auto&amp;quot;);;                 ## Die Warmwassersteuerung erfolgt wieder automatisch\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation active&amp;quot;);;                        ## Zirkulation wieder einschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_LWP() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP on&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 60.0&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;verwendet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_LWP() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 50.0&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr LWP_PV_Perl DbLogExclude .*&lt;br /&gt;
attr LWP_PV_Perl DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV_Perl alias LWP_PV_Perl&lt;br /&gt;
attr LWP_PV_Perl comment Version 2023.01.18 09:00&lt;br /&gt;
attr LWP_PV_Perl disable 0&lt;br /&gt;
attr LWP_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV_Perl icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV_Perl room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV_Perl sortby 411&lt;br /&gt;
attr LWP_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|::ReadingsTimestamp(&amp;quot;Heizung&amp;quot;,&amp;quot;counterHeatQTotal&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Status / LWP Status / Brauchwasser&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,04_1_LWP_Nachheizen_WW,04_2_LWP_Prioritaet_An,05___LWP_Ende,06___LWP_Prioritaet_Reset,07_1_Heizung_An,07_2_Heizung_Aus,07_3_Heizung_WZ_15_Grad,07_4_Heizung_WZ_22_Grad,07_5_Warmwasser_aus,07_6_Warmwasser_an&amp;quot;) |[Heizung:opStateHeatPump1].&amp;quot; &amp;quot;.[Heizung:opStateHeatPump2]|[Heizung:opStateHeatPump3]|FUNC_Status([Heizung:hotWaterTemperature],47,&amp;quot;orange&amp;quot;,[Heizung:hotWaterTemperature],&amp;quot;green&amp;quot;,[Heizung:hotWaterTemperature],53,&amp;quot;red&amp;quot;,[Heizung:hotWaterTemperature]).&amp;quot; °C&amp;quot;\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;PV-Modus / Heiz-Modus / Winter, Übergangszeit Heiz Start/Ende&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;PV-Modus:&amp;lt;br&amp;gt;&amp;quot;.[$SELF:LWP_Priority].&amp;quot; / &amp;quot;.(([$SELF:LWP_Status] ne &amp;quot;Aus&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039;)|&amp;quot;Heizung: &amp;quot;.[Heizung:opModeHeating].&amp;quot;&amp;lt;br&amp;gt;Warmwasser: &amp;quot;.[Heizung:opModeHotWater]|widget([$SELF:TimeStartHeizungWinter],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartHeizungUebergang],&amp;quot;time&amp;quot;)|[$SELF:TimeStartHeizung].widget([$SELF:TimeEndHeizung],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;Statistiken&amp;quot;|&amp;quot;Zähler&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Information&amp;quot;|&amp;quot;Wert&amp;quot;\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;EVU&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[EVU_StromZaehler:Strom_Status-02])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;LWP/KWL&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung_Zaehler])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHeating])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Warmwasser&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHotWater])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Photovoltaik&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQPool])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQTotal])\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 23:55:00 LWP_Priority frei&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-29 15:37:06 LWP_Status Aus&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 12:21:48 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 3000&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 2250&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-25 19:00:12 RunTimeMin 2400&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:55:35 RunTimePerDay 28800&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:37 TimeEnd 15:05&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 13:24:01 TimeEndHeizung 18:35&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:19 TimeStart 11:30&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 18:35:00 TimeStartHeizung 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:37:59 TimeStartHeizungUebergang 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:34:08 TimeStartHeizungWinter 02:05&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-31 12:05:34 ui_command_1 ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.54&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP&lt;br /&gt;
attr shelly01 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 412&lt;br /&gt;
attr shelly01 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung_Zaehler&amp;quot;,0));;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Wärmepumpe Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly01 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{4}(\.[0-9]{1})*$ StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{1,3}(\.[0-9]{1})*$&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter comment Version 2021.01.09 11:16&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 413&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39070</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39070"/>
		<updated>2024-02-08T11:46:12Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ ls -l docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1.txt Beispiel für WR_1]&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_2.txt Beispiel für WR_2]&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
Die KeyValue() Funktion kommt in die 99_myUtils.pm .&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Die plenticore_auth() kommt in die 99_myUtils.pm .&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/99_myUtils.pm_Erg%c3%a4nzungen.txt Beispiel 99_myUtils.pm Ergänzungen]&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Photovoltaik/Wechselrichter/RAW_WR_1_API.txt Beispiel WR_1_API]&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erweiterung im PV_Schedule, um die Zählerstände zu speichern&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 1)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_2_API DbLogExclude .*&lt;br /&gt;
attr WR_2_API DbLogInclude Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API authRetries 1&lt;br /&gt;
attr WR_2_API comment Version 2021.04.27 16:00\&lt;br /&gt;
Passworte für die Abfrage des WR_2_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_2_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_2_API disable 0&lt;br /&gt;
attr WR_2_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_2_API enableControlSet 0&lt;br /&gt;
attr WR_2_API enableCookies 1&lt;br /&gt;
attr WR_2_API event-on-update-reading auth_.*,Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API get01Data %START%&lt;br /&gt;
attr WR_2_API get01Name 01_auth_start&lt;br /&gt;
attr WR_2_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API get02Data %FINISH%&lt;br /&gt;
attr WR_2_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_2_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API get03Data %SESSION%&lt;br /&gt;
attr WR_2_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_2_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_2_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_2_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_2_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_2_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_2_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_2_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get04JSON .&lt;br /&gt;
attr WR_2_API get04Name 04_auth_me&lt;br /&gt;
attr WR_2_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_2_API get05-1Name info_api_version&lt;br /&gt;
attr WR_2_API get05-2Name info_hostname&lt;br /&gt;
attr WR_2_API get05-3Name info_name&lt;br /&gt;
attr WR_2_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_2_API get05JSON .&lt;br /&gt;
attr WR_2_API get05Name 05_info_version&lt;br /&gt;
attr WR_2_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_2_API get20-10Format %.2f&lt;br /&gt;
attr WR_2_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-11Format %.2f&lt;br /&gt;
attr WR_2_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-12Format %.2f&lt;br /&gt;
attr WR_2_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-13Format %.2f&lt;br /&gt;
attr WR_2_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_2_API get20-14Format %.2f&lt;br /&gt;
attr WR_2_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_2_API get20-15Format %.2f&lt;br /&gt;
attr WR_2_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_2_API get20-16Format %.2f&lt;br /&gt;
attr WR_2_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_2_API get20-17Format %.2f&lt;br /&gt;
attr WR_2_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_2_API get20-18Format %.2f&lt;br /&gt;
attr WR_2_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_2_API get20-19Format %.2f&lt;br /&gt;
attr WR_2_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_2_API get20-1Format %.2f&lt;br /&gt;
attr WR_2_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_2_API get20-20Format %.2f&lt;br /&gt;
attr WR_2_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_2_API get20-21Format %.2f&lt;br /&gt;
attr WR_2_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_2_API get20-22Format %.2f&lt;br /&gt;
attr WR_2_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_2_API get20-23Format %.2f&lt;br /&gt;
attr WR_2_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_2_API get20-24Format %.2f&lt;br /&gt;
attr WR_2_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_2_API get20-25Format %.2f&lt;br /&gt;
attr WR_2_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_2_API get20-26Format %.2f&lt;br /&gt;
attr WR_2_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-27Format %.2f&lt;br /&gt;
attr WR_2_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-28Format %.2f&lt;br /&gt;
attr WR_2_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-29Format %.2f&lt;br /&gt;
attr WR_2_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_2_API get20-2Format %.2f&lt;br /&gt;
attr WR_2_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_2_API get20-30Format %.2f&lt;br /&gt;
attr WR_2_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_2_API get20-31Format %.2f&lt;br /&gt;
attr WR_2_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_2_API get20-32Format %.2f&lt;br /&gt;
attr WR_2_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_2_API get20-33Format %.2f&lt;br /&gt;
attr WR_2_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_2_API get20-34Format %.2f&lt;br /&gt;
attr WR_2_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_2_API get20-35Format %.2f&lt;br /&gt;
attr WR_2_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_2_API get20-36Format %.2f&lt;br /&gt;
attr WR_2_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_2_API get20-37Format %.2f&lt;br /&gt;
attr WR_2_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_2_API get20-38Format %.2f&lt;br /&gt;
attr WR_2_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_2_API get20-39Format %.2f&lt;br /&gt;
attr WR_2_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_2_API get20-3Format %.2f&lt;br /&gt;
attr WR_2_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_2_API get20-40Format %.2f&lt;br /&gt;
attr WR_2_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_2_API get20-41Format %.2f&lt;br /&gt;
attr WR_2_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_2_API get20-42Format %.2f&lt;br /&gt;
attr WR_2_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_2_API get20-43Format %.2f&lt;br /&gt;
attr WR_2_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_2_API get20-44Format %.2f&lt;br /&gt;
attr WR_2_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_2_API get20-45Format %.2f&lt;br /&gt;
attr WR_2_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_2_API get20-46Format %.2f&lt;br /&gt;
attr WR_2_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_2_API get20-47Format %.2f&lt;br /&gt;
attr WR_2_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_2_API get20-48Format %.2f&lt;br /&gt;
attr WR_2_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_2_API get20-49Format %.2f&lt;br /&gt;
attr WR_2_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_2_API get20-4Format %.2f&lt;br /&gt;
attr WR_2_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_2_API get20-50Format %.2f&lt;br /&gt;
attr WR_2_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_2_API get20-51Format %.2f&lt;br /&gt;
attr WR_2_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_2_API get20-52Format %.2f&lt;br /&gt;
attr WR_2_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_2_API get20-53Format %.2f&lt;br /&gt;
attr WR_2_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_2_API get20-54Format %.2f&lt;br /&gt;
attr WR_2_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_2_API get20-55Format %.2f&lt;br /&gt;
attr WR_2_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_2_API get20-56Format %.2f&lt;br /&gt;
attr WR_2_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_2_API get20-57Format %.2f&lt;br /&gt;
attr WR_2_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_2_API get20-58Format %.2f&lt;br /&gt;
attr WR_2_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_2_API get20-59Format %.2f&lt;br /&gt;
attr WR_2_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_2_API get20-5Format %.2f&lt;br /&gt;
attr WR_2_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_2_API get20-60Format %.2f&lt;br /&gt;
attr WR_2_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_2_API get20-61Format %.2f&lt;br /&gt;
attr WR_2_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_2_API get20-62Format %.2f&lt;br /&gt;
attr WR_2_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_2_API get20-63Format %.2f&lt;br /&gt;
attr WR_2_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_2_API get20-64Format %.2f&lt;br /&gt;
attr WR_2_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_2_API get20-65Format %.2f&lt;br /&gt;
attr WR_2_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_2_API get20-6Format %.2f&lt;br /&gt;
attr WR_2_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_2_API get20-7Format %.2f&lt;br /&gt;
attr WR_2_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_2_API get20-8Format %.2f&lt;br /&gt;
attr WR_2_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_2_API get20-9Format %.2f&lt;br /&gt;
attr WR_2_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_2_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_2_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_2_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_2_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get40Name 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable&lt;br /&gt;
attr WR_2_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_2_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_2_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_2_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get60Name 60_update_status&lt;br /&gt;
attr WR_2_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_2_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_2_API icon sani_solar&lt;br /&gt;
attr WR_2_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_2_API reading0101JSON nonce&lt;br /&gt;
attr WR_2_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_2_API reading0102JSON rounds&lt;br /&gt;
attr WR_2_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_2_API reading0103JSON salt&lt;br /&gt;
attr WR_2_API reading0103Name auth_salt&lt;br /&gt;
attr WR_2_API reading0104JSON transactionId&lt;br /&gt;
attr WR_2_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_2_API reading0201JSON signature&lt;br /&gt;
attr WR_2_API reading0201Name auth_signature&lt;br /&gt;
attr WR_2_API reading0202JSON token&lt;br /&gt;
attr WR_2_API reading0202Name auth_token&lt;br /&gt;
attr WR_2_API reading0301JSON message&lt;br /&gt;
attr WR_2_API reading0301Name info_message&lt;br /&gt;
attr WR_2_API reading0302JSON error&lt;br /&gt;
attr WR_2_API reading0302Name info_error&lt;br /&gt;
attr WR_2_API reading03JSON sessionId&lt;br /&gt;
attr WR_2_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_2_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_2_API replacement01Mode expression&lt;br /&gt;
attr WR_2_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_2_API replacement01Value {ReadingsVal(&amp;quot;WR_2_config&amp;quot;,&amp;quot;IP-WR_2&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement02Mode expression&lt;br /&gt;
attr WR_2_API replacement02Regex %START%&lt;br /&gt;
attr WR_2_API replacement02Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement04Mode expression&lt;br /&gt;
attr WR_2_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_2_API replacement04Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement05Mode expression&lt;br /&gt;
attr WR_2_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_2_API replacement05Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement06Mode reading&lt;br /&gt;
attr WR_2_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_2_API replacement06Value auth_signature&lt;br /&gt;
attr WR_2_API replacement07Mode reading&lt;br /&gt;
attr WR_2_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_2_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_2_API replacement08Mode expression&lt;br /&gt;
attr WR_2_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_2_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API replacement09Mode expression&lt;br /&gt;
attr WR_2_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_2_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set06Method POST&lt;br /&gt;
attr WR_2_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_2_API set06NoArg 1&lt;br /&gt;
attr WR_2_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_2_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_2_API set4002FollowGet 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_2_API set4002Method PUT&lt;br /&gt;
attr WR_2_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_2_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_2_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_2_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_2_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_2_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_2_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_2_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_2_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_2_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_2_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_2_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_2_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_2_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_2_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_2_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_2_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_2_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_2_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_2_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_2_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_2_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_2_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_2_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_2_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_2_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_2_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_2_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_2_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_2_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_2_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_2_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_2_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_2_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_2_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_2_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_2_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_2_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_2_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_2_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_2_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_2_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_2_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_2_API set50JSON .&lt;br /&gt;
attr WR_2_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_2_API set50ParseResponse 1&lt;br /&gt;
attr WR_2_API set50TextArg 1&lt;br /&gt;
attr WR_2_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_2_API showBody 1&lt;br /&gt;
attr WR_2_API showError 1&lt;br /&gt;
attr WR_2_API sid01Data %START%&lt;br /&gt;
attr WR_2_API sid01ParseResponse 1&lt;br /&gt;
attr WR_2_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API sid02Data %FINISH%&lt;br /&gt;
attr WR_2_API sid02ParseResponse 1&lt;br /&gt;
attr WR_2_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API sid03Data %SESSION%&lt;br /&gt;
attr WR_2_API sid03ParseResponse 1&lt;br /&gt;
attr WR_2_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API sortby 212&lt;br /&gt;
attr WR_2_API timeout 7&lt;br /&gt;
attr WR_2_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion Solar_forecast() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive        An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning       Aus = momentan keine Steuerung&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0          0 = Es gibt kein Mittags Hoch. Wird aus Solar_forecast() gesetzt &lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der PV_1:Solar_middayhigh_fc0_start wird dann unlimitiert bis zur PV_1:Solar_middayhigh_fc0_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_ExternControl DOIF ################################################################################################################\&lt;br /&gt;
## 1 Speicher Status vom WR_1_Speicher_1 aktualisieren.\&lt;br /&gt;
##   Dies geschieht über das WR_1_API Device, da der Speicher direkt am Wechselrichter angeschlossen ist.\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_WR_1_Speicher_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [:52]                                                           ## jede Stunde\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 21_Battery_Information&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 22_Battery_InternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 23_Battery_ExternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_1  : Speicher Status abfrage&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Wenn die Ladung im Herbst/Winter unter MinSoc geht allen PV Überschuss in die Batterie laden\&lt;br /&gt;
##\&lt;br /&gt;
## Im Winter kann der MinSoc, durch den WR Eigenverbrauch, unterschritten werden, deshalb wird vorher auf\&lt;br /&gt;
## smarte_laden umgeschaltet, bis die Batterie wieder einen hohen Soc erreicht hat. Siehe cmd_3 laden_beendet\&lt;br /&gt;
##\&lt;br /&gt;
2_smart_Laden_start_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [WR_ctl:Yield_fc0_day] &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit]     ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
       and [WR_1:Act_state_of_charge] &amp;lt;= [WR_1_API:Battery_InternControl_MinSoc]  ## Achtung der Speicherstand wird zu niedrig\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100             ## Der Speicher steht auf Entladen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.1: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.1: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_smart_Laden_start_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [WB_1:lp_1_ChargeStat]      eq &amp;quot;loading&amp;quot;                        ## Ein Fahrzeug wird gerade geladen\&lt;br /&gt;
     and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;Aus&amp;quot;                            ## Der Speicher darf nicht zum Laden verwendet werden\&lt;br /&gt;
     or\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot;                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot; ) {\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before aktiv&amp;quot;);;                ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before inaktiv&amp;quot;);;              ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
    } else {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_2.2: WallBox es wird gerade geladen&amp;quot;};;       ## Der vorherige Zustand war schon bekannt\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.2: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.2: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Beim erreichen von 90% Soc die Entladung wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:SpeicherEntladung] eq &amp;quot;Automatik&amp;quot;                            ## Nur für den Automatik Modus\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100         ## Das Speicher Entladen ist geperrt\&lt;br /&gt;
       and\&lt;br /&gt;
       [WR_1:Act_state_of_charge] &amp;gt;= 80                                  ## Der Speicher ist bereits 80% voll\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell aktiviert\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.1: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.1: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_smart_Laden_beenden_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;inaktiv&amp;quot;                      ## Vorher war es nicht aktiv\&lt;br /&gt;
      )\&lt;br /&gt;
     or  [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;                             ## Der Speicher darf zum Laden verwendet werden\&lt;br /&gt;
     or  [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                       ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.2: Batterie wird mit &amp;quot;.[?$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.2: Batterie auf &amp;quot;.[?WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (    [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;\&lt;br /&gt;
        and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;) {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF cmd_3.2: MaxSOC Limitierung wegen Wallboxnutzung abgeschaltet&amp;quot;;;}\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Wenn vor dem WB_1 laden das smart_Laden aktiv gewesen ist geht es zurück in den Zustand\&lt;br /&gt;
## \&lt;br /&gt;
3_smart_Laden_umschalten_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;aktiv&amp;quot;                        ## Vorher war es nicht aktiv\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_umschalten_WB_1&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                        ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: WB_1 laden beendet, reaktivieren des smart_Laden&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.3: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.3: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Bei Zeitsteuerung und guter Prognose bei 40% wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Zeit\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [$SELF:SpeicherEntladung]  eq &amp;quot;Zeit&amp;quot;                            ## Nur für den Zeit Modus\&lt;br /&gt;
     and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]            ## Zeitfenster aktiv ist\&lt;br /&gt;
     and [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                        ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (\&lt;br /&gt;
            [WR_1:Act_state_of_charge] &amp;gt;= 40                             ## und einem Stand von Soc 40%\&lt;br /&gt;
        and\&lt;br /&gt;
            ([WR_ctl:Yield_fc0_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit]   ## wenn es heute oder \&lt;br /&gt;
          or [WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit])  ## morgen viel Leistung gibt\&lt;br /&gt;
       )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_zeit&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, SpeicherExternTrigger, freigegeben&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Die Leistungsprognose von &amp;quot;.[$SELF:SpeicherMinSOC_fc1_Limit].&amp;quot; wird überschritten&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;frei&amp;quot;);;                         ## Trigger freigeben\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                           ## Signalisiere entladen im stateFormat\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);; ## Speicher für Entladung freigeben\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Freigabe der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. ([07:00-16:00]\&lt;br /&gt;
4_Trigger\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]       ## Zeitfenster aktiv ist\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot;                               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot; ) {                             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;  ## Speicher für Entladung freigeben\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                            ## Signalisiere entladen im stateFormat\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_4  : SpeicherExternTrigger, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Sperren der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. [16:00-07:00]\&lt;br /&gt;
5_Trigger_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitEnde]-[$SELF:SpeicherZeitStart]]       ## Zeitfenster verlassen wurde\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger_sperren&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;## Speicher für Entladung sperren\&lt;br /&gt;
  set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                             ## Signalisiere gesperrt im stateFormat\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
    {Log 3, &amp;quot;$SELF cmd_5  : SpeicherExternTrigger, Entlademodus gesperrt (Tarif oder Trigger)&amp;quot;};;\&lt;br /&gt;
 }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
6_Kommando_Wiederholung\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [WR_1_API:Battery_Control] &amp;gt; 0 and                                ## Wenn die ExternControl am WR konfiguriert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatActive]  eq &amp;quot;An&amp;quot; and                      ## Wenn die ExternControl Aktiviert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatRunning] eq &amp;quot;An&amp;quot; and                      ## Wenn es  ExternControl Kommandos zum Senden gibt\&lt;br /&gt;
       [  {sunrise_abs(&amp;quot;HORIZON=+5.0&amp;quot;,0,&amp;quot;6:00&amp;quot;,&amp;quot;08:35&amp;quot;)}                 ## Innerhalb der Photovoltaik Zeit\&lt;br /&gt;
        - {sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)} ] and\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot; ) {              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   my $MaxChargePowerTime = 0;;\&lt;br /&gt;
   my $MaxChargePowerAbs_midday = 0;;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {                              ## Hier können noch Testmeldungen hin\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : SpeicherMiddayControlRunning &amp;quot;.[$SELF:SpeicherMiddayControlRunning];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_start   &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_stop    &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop];;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlRunning] eq &amp;quot;An&amp;quot; ) {                  ## Wurde ein Mittagshoch ermittelt und aktiviert?\&lt;br /&gt;
\&lt;br /&gt;
     if ( [WR_1:Act_state_of_charge] &amp;gt;= [WR_1_API:Battery_InternControl_MinSoc] *3 ) {\&lt;br /&gt;
       if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs 0&amp;quot;);;     ## nicht vor z.B. 09:00 Uhr starten. Ladung auf 0 Watt setzen\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                                              ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot; Uhr noch nicht laden&amp;quot;;;\&lt;br /&gt;
         }\&lt;br /&gt;
       } else {                                                          ## Ist noch Vormittag?\&lt;br /&gt;
         if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
           ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning]);;\&lt;br /&gt;
           set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMidday_MaxSOC].&#039;)&#039;);;\&lt;br /&gt;
           if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                       ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; limitieren&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning].&amp;quot; limitiert&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSOC auf &amp;quot;.[$SELF:SpeicherMidday_MaxSOC].&amp;quot; % limitiert&amp;quot;;;\&lt;br /&gt;
           }\&lt;br /&gt;
         }\&lt;br /&gt;
       }\&lt;br /&gt;
     } else {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_6  : Battery_InternControl_MinSoc auf &amp;quot;.([WR_1_API:Battery_InternControl_MinSoc] *3).&amp;quot; % laden&amp;quot;;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
     if (::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) &amp;lt;= time and  ## Es ist Mittag\&lt;br /&gt;
         time &amp;lt;= ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
\&lt;br /&gt;
       my $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;)+3600 ));;\&lt;br /&gt;
          $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ));;\&lt;br /&gt;
\&lt;br /&gt;
       if ([$SELF:SpeicherMaxSOCControlRunning] eq &amp;quot;An&amp;quot; and                     ## Somit bleibt weniger Platz im Speicher und es ist\&lt;br /&gt;
           time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.$wait.&amp;quot;:00&amp;quot;) ) {  ## besser nicht zu früh beginnen.\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden wegen MaxSoc von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; auf &amp;quot;.$wait.&amp;quot; Uhr verschoben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
       } else {                                                                 ## auch jetzt nicht mit voller Leistung laden\&lt;br /&gt;
\&lt;br /&gt;
         if ([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0) {            ## dynamische Leistungsermittlung oder vorgewählter Wert\&lt;br /&gt;
           $MaxChargePowerTime       = ::round((::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) - time) / 3600 , 2);;  ## Mittags Ladezeit bestimmen\&lt;br /&gt;
\&lt;br /&gt;
           my $MaxChargePowerLimit   = (1 - ::round($MaxChargePowerTime,2) * [$SELF:SpeicherMidday_MaxChargePowerSteigung]);;  ## Zu Beginn etwas langsamer anfangen, empirisch ermittelt\&lt;br /&gt;
\&lt;br /&gt;
           $MaxChargePowerAbs_midday = ::round( [WR_1:Battery_work_capacity] * ([$SELF:SpeicherMaxSOC_Actual] - [WR_1:Act_state_of_charge]) / 100 * $MaxChargePowerLimit, 0);;\&lt;br /&gt;
\&lt;br /&gt;
           if ($MaxChargePowerAbs_midday &amp;lt; 500) { $MaxChargePowerAbs_midday = 500 };;## Nicht unter 1000\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Mittags $MaxChargePowerTime h mit $MaxChargePowerAbs_midday W laden&amp;quot;;;\&lt;br /&gt;
         } else {\&lt;br /&gt;
           $MaxChargePowerAbs_midday = [$SELF:SpeicherMidday_MaxChargePowerAbs_midday];; ## Nimm den vorgewählten Wert\&lt;br /&gt;
         };;\&lt;br /&gt;
\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs $MaxChargePowerAbs_midday&amp;quot;);;\&lt;br /&gt;
         set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMaxSOC_Actual].&#039;)&#039;);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; bis &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; freigegeben&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf $MaxChargePowerAbs_midday limitiert&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;\&lt;br /&gt;
         };;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
\&lt;br /&gt;
     if (time &amp;gt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {    ## Es ist Nachmittag und die\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                                         ## Mittagssteuerung wird abgeschaltet\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl nach &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; beendet&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;An&amp;quot; and ## Nur MaxSOC soll begrenzt werden\&lt;br /&gt;
       [$SELF:SpeicherMaxSOC_Actual] &amp;lt;= 100                        and                                          \&lt;br /&gt;
       ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;Aus&amp;quot;) { ##  sobald die Mittagssteuerung fertig ist\&lt;br /&gt;
     if ([WR_1:SW_Home_own_consumption_from_Battery] &amp;gt; 500) {             ## Sollte der Speicher bereits jetzt verwendet werden ist es besser\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                 ## die MaxSOC Begrenzung zu stoppen\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMaxSOCControl wegen Speicher Nutzung am Nachmittag beendet&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_6  : ExternControl Kommando Wiederholung erledigt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Bestimmung eines möglichen SOC für den nächsten Morgen und\&lt;br /&gt;
##   Vorbereitung für ein Leistungshoch am Mittag\&lt;br /&gt;
##\&lt;br /&gt;
7_SOC_Calculation\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       ([WR_1_API:Battery_Control] &amp;gt; 0 and                               ## Ist die ExternControl am WR aktiviert\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot;   or                ## Ist MaxSOC Limit konfiguriert\&lt;br /&gt;
         [$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; ) and               ## Ist Midday Kontrolle konfiguriert\&lt;br /&gt;
        [$SELF:SpeicherMaxSOC_MinSOC_Time]  eq &amp;quot;NULL&amp;quot; and                ## Wurde ein minimum SOC bereits ermittelt\&lt;br /&gt;
        [{sunrise_abs(&amp;quot;HORIZON=+4.0&amp;quot;,0,&amp;quot;5:50&amp;quot;,&amp;quot;08:35&amp;quot;)} - 10:00 ] and\&lt;br /&gt;
        [WR_1:SW_Home_own_consumption_from_PV] == [WR_1:SW_Home_own_consumption] ## Die PV Leistung reicht für&#039;s Haus\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot; ) {                     ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   my $MinSOC_Time   = &amp;quot;gefunden&amp;quot;;;                                       ## Nur einmal am Tag bearbeiten\&lt;br /&gt;
   my $MinSOC_MinSOC = ::round([WR_1:Act_state_of_charge],0);;            ## Festgestellter MinSOC am Morgen          Magic ???\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,$MinSOC_Time);;\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,$MinSOC_MinSOC);;\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                               ## merken und melden\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_MinSOC_Time &amp;quot;.$MinSOC_Time.&amp;quot; &amp;quot;.$MinSOC_MinSOC.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot; and\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt; 100 and     ## Der Speicher darf nicht im smart_laden sein\&lt;br /&gt;
       [Pool_Counter:countsPerDay] == 0 and                              ## Achtung der Pool und auch die LWP\&lt;br /&gt;
       [LWP_Counter:countsPerDay]  == 0 ) {                              ##    sollten nicht mehr früh morgens laufen\&lt;br /&gt;
\&lt;br /&gt;
     my $SpeicherSOCMinimum = [WR_1_API:Battery_InternControl_MinSoc]*3;; ## 3x MinSOC als reserve vorsehen\&lt;br /&gt;
     my $SpeicherSOCDayBefore = ::round(ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;, 100),0);; ## wie voll war er gestern noch?\&lt;br /&gt;
     my $SpeicherSOCNew       = 0;;\&lt;br /&gt;
     my $SpeicherSOCDelta     = 0;;\&lt;br /&gt;
\&lt;br /&gt;
     if ([WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMaxSOC_fc1_Limit] and\&lt;br /&gt;
         $MinSOC_MinSOC                   &amp;gt; $SpeicherSOCMinimum ) {      ## Ist der Speicher voller als er müsste?\&lt;br /&gt;
\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Leistung Prognose &amp;quot;.[WR_ctl:Yield_fc1_day].&amp;quot; wh &amp;gt; Schwellwert &amp;quot;.[$SELF:SpeicherMaxSOC_fc1_Limit].&amp;quot; wh&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Speicherladung aktuell $MinSOC_MinSOC % &amp;gt; Minimum $SpeicherSOCMinimum %&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
       $SpeicherSOCDelta = $MinSOC_MinSOC - $SpeicherSOCMinimum;;         ## Was wäre noch übrig?\&lt;br /&gt;
       if ($SpeicherSOCDelta &amp;lt;= 10) {                                    ## Das lohnt sich nicht\&lt;br /&gt;
         $SpeicherSOCNew = $SpeicherSOCDayBefore;;                        ## den Wert von gestern einfach beibehalten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCDayBefore);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; % gesichert&amp;quot;};;\&lt;br /&gt;
       } else {\&lt;br /&gt;
         $SpeicherSOCNew = ::round(($SpeicherSOCDayBefore+$SpeicherSOCDayBefore-$SpeicherSOCDelta)/2 ,0);;  ## um den Durchschnitt verringern\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCNew);;           ## Das soll heute in den Speicher\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCNew.&amp;quot; % neu berechnet und gesichert&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
       if ($SpeicherSOCNew &amp;gt; 0) {                                        ## Es gibt einen neuen MaxSoc\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;               ## Senden starten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Wiederholung starten\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual &amp;quot;.$SpeicherSOCNew.&amp;quot; % geplant&amp;quot;};;\&lt;br /&gt;
       } else {                                                          ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
     } else {                                                            ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
       if ($MinSOC_MinSOC  &amp;lt; $SpeicherSOCMinimum ) {                     ## MaxSoc leicht erhöhen, da er etwas zu niedrig war\&lt;br /&gt;
         $SpeicherSOCNew   = ::round($SpeicherSOCDayBefore+$SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         $SpeicherSOCDelta = ::round($SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,$SpeicherSOCNew);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore wurde um &amp;quot;.$SpeicherSOCDelta.&amp;quot; erhöht&amp;quot;};;\&lt;br /&gt;
       }\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt, da die Prognose für morgen zu schlecht ist&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; and                   ## Soll für mittags noch Platz gehalten werden?\&lt;br /&gt;
       [WR_ctl:Yield_fc0_middayhigh] == 1 ) {                                                    \&lt;br /&gt;
																	                           \&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Die Mittagskontrolle aktivieren\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){                              ## (die Uhrzeiten wurden bereits durch Solar_forecast() im WR_1 Device eingetragen)\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie SpeicherMiddayControlRunning vorbereitet&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_start &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_start&amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_stop  &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_stop &amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {                                                              ## Kein Mittagshoch\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMiddayControl es wird kein Middayhigh geben&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Reset der ExternControl Kommandos\&lt;br /&gt;
##\&lt;br /&gt;
8_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;16:00&amp;quot;,&amp;quot;21:00&amp;quot;)}]                ## hier sollte das Ende der PV-Zeit sein\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot;                                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot; ) {                               ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
																			                   \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Max SOC Steuerung zurücksetzen\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                           ## SpeicherMaxSOC_Actual auf Default\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,[WR_1:Act_state_of_charge]);;   ## Den vor Tages Wert merken\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,&amp;quot;NULL&amp;quot;);;                     ## Die MinSOC Time löschen\&lt;br /&gt;
																						       \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Midday Steuerung zurücksetzen\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_8  : ExternControl zurückgesetzt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird, das ist dann im Herbst/Winter\&lt;br /&gt;
##\&lt;br /&gt;
9_MinSOC_Winter\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit] and        ## Wenn morgen das Minimum an Leistung nicht erreicht wird\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;lt; [$SELF:SpeicherMinSOC_Winter]    and        ## und der MinSoc unter der Winter Wert eingestellt ist\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot; or\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;NULL&amp;quot; and [10:01])\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Winter]);;        ## Den MinSOC anheben, um eine eventuelle\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : Batterie MinSoc auf Winterbetrieb&amp;quot;};;        ## Notladung zu verhindern\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Im Winter Betrieb keine MaxSOC Begrenzung\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## und keine Midday Steuerung\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : MaxSOC Begrenzung und Midday Steuerung im Winterbetrieb deaktiviert&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Umschaltung des MinSoc wenn viel Leistung erwartet wir, das wäre dann Frühling/Sommer\&lt;br /&gt;
##\&lt;br /&gt;
10_MinSOC_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit] and         ## sobald viel Ladung erwartet wird und der MinSoc noch\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;gt; [$SELF:SpeicherMinSOC_Sommer]    and         ## noch im Winter Modus ist\&lt;br /&gt;
        [10:09] \&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
                                                                                           \&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Sommer]);;        ## den MinSOC auf Sommerbetrieb herabsetzen, es kann\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_10 : Batterie MinSoc auf Sommerbetrieb&amp;quot;};;                              ## wieder mehr Leistung genutzt werden\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Der Speicher ist voll geladen. Hier wird das ständige nachladen auf 100 % vermieden.\&lt;br /&gt;
##\&lt;br /&gt;
11_Speicher_voll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ( [WR_ctl:Yield_fc0_day]        &amp;gt;  [$SELF:SpeicherMaxSOC_fc1_Limit] and    ## 1) sobald viel Leistung erwartet wird und der Speicher voll ist\&lt;br /&gt;
         [WR_1:Act_state_of_charge]    == 100                              and    ##    den MaxSOC wieder reduzieren, damit nicht immer nachgeladen wird\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_Actual] ne 95                                      ##   \&lt;br /&gt;
        or\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_Actual] == 95 and                                  ## 2) oder das Nachladen gestoppt wurde\&lt;br /&gt;
         [WR_1:Act_state_of_charge] &amp;lt;=  98  and                                   ##    und der SOC unte 98 % gefallen ist\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,-7200,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)}])                    ##    zwei Stunden vor Sonnenuntergang eventuell wieder nachladen\&lt;br /&gt;
       ) and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot; ) {                       ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([WR_1:Act_state_of_charge] &amp;lt;= 98) {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                         ## Eventuell noch mal nachladen\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 100 % nachladen&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;95&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                       ## Start regelmäßiges senden der Kommandos\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## MaxSOC Begrenzung weil Speicher bereits 100 % hat\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 95 % reduziert&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 WR_1_Speicher_1 DC_Power_Abs setzen z.B. zur Zwangsentladung\&lt;br /&gt;
##     dies muss manuell wiederholt werden. Danach hängt es vom WR ab, wie er die Speichersteuerung fortsetzt.\&lt;br /&gt;
12_DC_Power_Abs \&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot;                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot; ) {                        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs &amp;quot;.[$SELF:SpeicherDcPowerAbs]);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_12 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 13 WR_1_Speicher_1 Status aktualisieren.\&lt;br /&gt;
##   Dies ist momentan nur für den BYD HV Speicher, da der BYD HVS eine direkte Abfrage nicht unterstützt.\&lt;br /&gt;
##   Wer keinen BYD HV Speicher hat kann das löschen\&lt;br /&gt;
13_Status_WR_1_Speicher_1_BYD\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
      or\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot; ) {          ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 BatteryInformation&amp;quot;);;\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 StatisticInformation&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_13 : Speicher Status abfrage, BYD HV direkt&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 14_Lüfter_ein\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 15_Lüfter_aus\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 17 Wiederhole alle 180s das Kommando für die DcPowerAbs Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
17_Kommando_Wiederholung_DcPowerAbs\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [$SELF:SpeicherTriggerLaden] eq &amp;quot;An&amp;quot;  and                         ## Ist der Trigger für das Zwangsladen aktiv?\&lt;br /&gt;
       [$SELF:SpeicherDcPowerAbs]   ne 0     and                         ## Wurde eine Lade/Entlade Leistung eingestellt?\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot; ) {   ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs [$SELF:SpeicherDcPowerAbs]&amp;quot;);;\&lt;br /&gt;
   set_Exec(&amp;quot;17_Battery_EM_State&amp;quot;,30,&#039;::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;)&#039;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_17 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl alias WR_1_Speicher_1_ExternControl&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl comment Version 2023.06.21 14:00\&lt;br /&gt;
\&lt;br /&gt;
Hier können externe Trigger für die Ladung und Entladung Der Batterie gesetzt werden.\&lt;br /&gt;
Die Zeiten können z.B. durch den WeekDayTimer entsprechend an einen Stromtarif angepasst werden.\&lt;br /&gt;
Das reading SpeicherEntladung Automatik/Zeit/SpeicherTrigger ermöglicht es die Zeitsteuerung zu überschreiben.\&lt;br /&gt;
\&lt;br /&gt;
ExternTrigger\&lt;br /&gt;
Das reading dient dem Freigeben und Sperren der externen Trigger, z.B. um im Herbst/Winter das smart_laden zu steuern.\&lt;br /&gt;
Es verriegelt somit die Zeitsteuerung oder den SpeicherTrigger.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger \&lt;br /&gt;
Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API\&lt;br /&gt;
Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst\&lt;br /&gt;
SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung\&lt;br /&gt;
\&lt;br /&gt;
SpeicherTrigger:entladen,gesperrt\&lt;br /&gt;
Dieser Trigger kann durch ander Logik gesetzt werden.\&lt;br /&gt;
Auch hier wäre eine Zeitsteuerung denkbar, die entladen/gesperrt entsprechend umschaltet.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherZeitStart/SpeicherZeitEnde\&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.\&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.\&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.\&lt;br /&gt;
\&lt;br /&gt;
Speicher*ControlActive\&lt;br /&gt;
Das jeweilige reading aktiviert diese Teilkomponente für die Steuerung.\&lt;br /&gt;
Ein jeweiliges Speicher*ControlRunning signalisiert, ob gerade die Bedingungen erfüllt sind.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherCmdRepeatActive\&lt;br /&gt;
Es muss im WR die externe Speicher Steuerung aktiviert sein.\&lt;br /&gt;
Möchte man trotzdem die Sendung der ExternControl Kommandos stoppen, obwohl die Bedingungen erfüllt sind,\&lt;br /&gt;
kann man dieses reading zum Deaktivieren auf 0 setzen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMiddayControl\&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMaxSOCControl\&lt;br /&gt;
Es wird versucht den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMinSOC\&lt;br /&gt;
Dies gehört zur Basis Steuerung und schaltet den MinSOC von Sommer auf Winter Betrieb,\&lt;br /&gt;
um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl disable 0&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl readingList SpeicherExternTrigger SpeicherCmdRepeatActive SpeicherZeitStart SpeicherZeitEnde SpeicherEntladung SpeicherTrigger SpeicherMiddayControlActive SpeicherMidday_Inverter_Max_Power SpeicherMidday_MaxChargePowerAbs_morning SpeicherMidday_MaxChargePowerAbs_midday SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC SpeicherMidday_NotBefore SpeicherMinSOC_Sommer SpeicherMinSOC_Winter SpeicherMinSOC_fc1_Limit SpeicherMaxSOCControlActive SpeicherMaxSOC_Actual SpeicherMaxSOC_DayBefore SpeicherMaxSOC_fc1_Limit&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl setList SpeicherExternTrigger:frei,gesperrt SpeicherCmdRepeatActive:0,1 SpeicherZeitStart:time SpeicherZeitEnde:time SpeicherEntladung:Automatik,Zeit,Trigger SpeicherTrigger:entladen,gesperrt,none SpeicherMiddayControlActive:0,1 SpeicherMidday_Inverter_Max_Power:slider,3000,500,20000 SpeicherMidday_MaxChargePowerAbs_morning:slider,0,50,1000 SpeicherMidday_MaxChargePowerAbs_midday:slider,0,100,4700 SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC:slider,20,5,50 SpeicherMidday_NotBefore:time SpeicherMinSOC_Sommer:slider,5,1,20 SpeicherMinSOC_Winter:slider,5,1,20 SpeicherMinSOC_fc1_Limit:slider,7000,500,17000 SpeicherMaxSOCControlActive:0,1 SpeicherMaxSOC_Actual:slider,60,5,100 SpeicherMaxSOC_DayBefore:slider,15,5,100 SpeicherMaxSOC_fc1_Limit:slider,10000,2000,50000&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl sortby 122&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
#########################################################\&lt;br /&gt;
## &amp;quot;Spalte 0&amp;quot;|&amp;quot;Spalte 1&amp;quot;|&amp;quot;Spalte 2&amp;quot;|&amp;quot;Spalte 3&amp;quot;|&amp;quot;Spalte 4&amp;quot;|&amp;quot;Spalte 5&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / DcPowerAbs / Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_Speicher,smart_Laden_start,smart_Laden_beenden,smart_Laden_starten_WB_1,smart_Laden_beenden_WB_1,Kommando_Wiederholung,SOC_Calculation,Reset,DC_Power_Abs,Sommer,Winter,Speicher_voll,14_Luefter_ein,15_Luefter_aus,Status_WR_1_Speicher_1_BYD&amp;quot;) | widget([$SELF:SpeicherDcPowerAbs],&amp;quot;selectnumbers,-4500,250,4500,0,lin&amp;quot;).&amp;quot;W&amp;quot;.widget([$SELF:SpeicherTriggerLaden],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |[WR_1_API:Battery_EM_State]|([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and [WR_1_API:Battery_InternControl_MinHomeConsumption] == 30000)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;smart_Laden aktiv&amp;lt;/span&amp;gt;&#039;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Speicher&amp;lt;dd&amp;gt;Steuerung&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherEntladung],&amp;quot;uzsuDropDown,Automatik,Trigger,Zeit&amp;quot;) |&amp;quot;WB_1 Laden &amp;quot;.widget([$SELF:SpeicherWB_1_buffer],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|\&lt;br /&gt;
FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,&amp;quot;Laden&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Standby&amp;quot;,15,&amp;quot;red&amp;quot;,&amp;quot;Entladen&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_Status([WR_1:Act_state_of_charge],15,&amp;quot;red&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,49,&amp;quot;green&amp;quot;,&amp;quot;Speicher SOC&amp;quot;)|\&lt;br /&gt;
\&lt;br /&gt;
 FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],&amp;quot;orange&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],15,&amp;quot;red&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P]).&amp;quot; W&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([WR_1:Act_state_of_charge])).STY(::round([WR_1:Act_state_of_charge],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Trigger&amp;lt;dd&amp;gt;Status / ExternTrigger / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherTrigger],&amp;quot;uzsuDropDown,entladen,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherExternTrigger],&amp;quot;uzsuDropDown,frei,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherZeitStart],&amp;quot;time&amp;quot;) | widget([$SELF:SpeicherZeitEnde],&amp;quot;time&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Kommando Wiederholung&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherCmdRepeatActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherCmdRepeatRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMaxSOCControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMaxSOCControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Limit&amp;lt;dd&amp;gt;fc1_Limit / Minimum SOC Zeit / gestern / geplant&amp;lt;/dd&amp;gt;&amp;quot; |\&lt;br /&gt;
FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMaxSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;). widget([$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;) | ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot;)?(POSIX::strftime(&amp;quot;%H:%M&amp;quot;,::localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,&amp;quot;&amp;quot;)))).&amp;quot; &amp;quot;.[$SELF:SpeicherMaxSOC_MinSOC_MinSOC].&amp;quot; %&amp;quot;):&amp;quot;wartet&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_DayBefore])).STY(&amp;quot;gestern&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_DayBefore],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_Actual])).STY(&amp;quot;geplant&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_Actual],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMiddayControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMiddayControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Limits&amp;lt;dd&amp;gt;Inverter_Max_Power / Laden nicht vor / Start /Stop&amp;lt;br&amp;gt;MaxSOC morgens / Power morgens / Power mittags&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMidday_Inverter_Max_Power],&amp;quot;selectnumbers,1000,250,15000,0,lin&amp;quot;).&amp;quot;W&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:SpeicherMidday_MaxSOC],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; | widget([$SELF:SpeicherMidday_NotBefore],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_morning],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_start],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_midday],&amp;quot;selectnumbers,0,100,4700,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_stop],&amp;quot;time&amp;quot;).([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0)?&amp;quot;dynamisch&amp;quot;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MinSOC Steuerung&amp;lt;dd&amp;gt;fc1_Limit / Winter | Sommer /aktuell&amp;lt;/dd&amp;gt;&amp;quot;|\&lt;br /&gt;
 FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMinSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;).widget([$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;).&amp;quot;wh&amp;quot; |\&lt;br /&gt;
 widget([$SELF:SpeicherMinSOC_Winter],&amp;quot;selectnumbers,10,1,30,0,lin&amp;quot;).widget([$SELF:SpeicherMinSOC_Sommer],&amp;quot;selectnumbers,5,1,10,0,lin&amp;quot;).&amp;quot;%&amp;quot; |&amp;quot;&amp;quot;|[WR_1_API:Battery_InternControl_MinSoc].&amp;quot; %&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherCmdRepeatActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherCmdRepeatRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-11 17:23:40 SpeicherDcPowerAbs 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:13 SpeicherEntladung Automatik&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherExternTrigger none&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherMaxSOCControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOCControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOC_Actual 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMaxSOC_DayBefore 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_MinSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_Time NULL&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:38:43 SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:27 SpeicherMiddayControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMiddayControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:12 SpeicherMidday_Inverter_Max_Power 9000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-08 11:21:31 SpeicherMidday_MaxChargePowerAbs_midday 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:31 SpeicherMidday_MaxChargePowerAbs_morning 450&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:28 SpeicherMidday_MaxSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-03 09:21:27 SpeicherMidday_NotBefore 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 18:45:27 SpeicherMinSOC_Sommer 5&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:54 SpeicherMinSOC_Winter 20&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-15 08:04:40 SpeicherMinSOC_fc1_Limit 16000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:05 SpeicherTrigger entladen&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 16:10:24 SpeicherZeitEnde 19:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:41:25 SpeicherZeitStart 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 WB_1_smart_laden_before ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1 ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;&#039;&#039;&#039;disable 1&#039;&#039;&#039;&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_0_KSEM ModbusAttr 1 60 192.168.178.xyz:502 TCP&lt;br /&gt;
attr WR_0_KSEM DbLogExclude .*&lt;br /&gt;
attr WR_0_KSEM DbLogInclude Active_energy.*&lt;br /&gt;
attr WR_0_KSEM alias WR_0_KSEM&lt;br /&gt;
attr WR_0_KSEM comment Version 2021.04.07 12:00\&lt;br /&gt;
Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\&lt;br /&gt;
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\&lt;br /&gt;
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\&lt;br /&gt;
\&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\&lt;br /&gt;
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\&lt;br /&gt;
\&lt;br /&gt;
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
attr WR_0_KSEM dev-h-defPoll 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr WR_0_KSEM disable 0&lt;br /&gt;
attr WR_0_KSEM event-on-change-reading Active_energy.*,M_AC_Current_.*&lt;br /&gt;
attr WR_0_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr WR_0_KSEM icon measure_power&lt;br /&gt;
attr WR_0_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr WR_0_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr WR_0_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr WR_0_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40075-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr WR_0_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr WR_0_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr WR_0_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40084-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40086-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40087-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr WR_0_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr WR_0_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr WR_0_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40091-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40096-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr WR_0_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr WR_0_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr WR_0_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40101-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr WR_0_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr WR_0_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr WR_0_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr WR_0_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr WR_0_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h512-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr WR_0_KSEM obj-h512-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h516-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr WR_0_KSEM obj-h516-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr WR_0_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr WR_0_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr WR_0_KSEM obj-h8196-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr WR_0_KSEM obj-h8212-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr WR_0_KSEM obj-h8228-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr WR_0_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr WR_0_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_0_KSEM sortby 140&lt;br /&gt;
attr WR_0_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr WR_0_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===BYD HV Speicher (mit HTTPMOD)===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort wird mit KeyValue() (siehe oben) verwaltet.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Der BYD HV Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
 - Die erste Abfrage führt das Login durch&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num *&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
&lt;br /&gt;
======KeyValue() speichern======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline aufgerufen werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition WR_1_Speicher_1 (BYD HV)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1 HTTPMOD http://%IP-WR_1_Speicher_1%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr WR_1_Speicher_1 DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1 DbLogInclude BatteryInformation_TotalVoltage,BatteryInformation_SOC,BatteryInformation_SOC,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 authRetries 1&lt;br /&gt;
attr WR_1_Speicher_1 comment Version 2021.04.07 12:00&lt;br /&gt;
attr WR_1_Speicher_1 dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_Speicher_1 enableControlSet 0&lt;br /&gt;
attr WR_1_Speicher_1 enableCookies 1&lt;br /&gt;
attr WR_1_Speicher_1 event-on-change-reading auth_.*,Battery.*_.*,Device.*_.*,Installation.*_.*,Array_.*,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 event-on-update-reading Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr WR_1_Speicher_1 get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr WR_1_Speicher_1 get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr WR_1_Speicher_1 get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr WR_1_Speicher_1 get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr WR_1_Speicher_1 get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr WR_1_Speicher_1 get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr WR_1_Speicher_1 get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr WR_1_Speicher_1 get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr WR_1_Speicher_1 get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr WR_1_Speicher_1 get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr WR_1_Speicher_1 get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr WR_1_Speicher_1 get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr WR_1_Speicher_1 get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr WR_1_Speicher_1 get01-16Name Array_Main_Current&lt;br /&gt;
attr WR_1_Speicher_1 get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr WR_1_Speicher_1 get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr WR_1_Speicher_1 get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr WR_1_Speicher_1 get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr WR_1_Speicher_1 get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr WR_1_Speicher_1 get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr WR_1_Speicher_1 get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr WR_1_Speicher_1 get01-22Name Array_Main_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr WR_1_Speicher_1 get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-73Name Array_Main_Power&lt;br /&gt;
attr WR_1_Speicher_1 get01-80Name Array_Series_Battery&lt;br /&gt;
attr WR_1_Speicher_1 get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr WR_1_Speicher_1 get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get01Name RunData&lt;br /&gt;
attr WR_1_Speicher_1 get01RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get02Name StatisticInformation&lt;br /&gt;
attr WR_1_Speicher_1 get02RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get02URL http://%IP-WR_1_Speicher_1%/asp/StatisticInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr WR_1_Speicher_1 get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr WR_1_Speicher_1 get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03Name DeviceInformation&lt;br /&gt;
attr WR_1_Speicher_1 get03RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get03URL http://%IP-WR_1_Speicher_1%/asp/DeviceInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-37Name BatteryInformation_Power&lt;br /&gt;
attr WR_1_Speicher_1 get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr WR_1_Speicher_1 get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-9Name BatteryInformation_Current&lt;br /&gt;
attr WR_1_Speicher_1 get04DeleteIfUnmatched 1&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get04Name BatteryInformation&lt;br /&gt;
attr WR_1_Speicher_1 get04RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr WR_1_Speicher_1 get04URL http://%IP-WR_1_Speicher_1%/asp/Home.asp&lt;br /&gt;
attr WR_1_Speicher_1 get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr WR_1_Speicher_1 get05Name InstallationConfig&lt;br /&gt;
attr WR_1_Speicher_1 get05RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get05URL http://%IP-WR_1_Speicher_1%/asp/UserInfo.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Data ArrayNum=1&amp;amp;SeriesBatteryNum=4&lt;br /&gt;
attr WR_1_Speicher_1 get10Header01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 get10Header02 Referer: http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Header03 Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
attr WR_1_Speicher_1 get10Header04 Accept: text/html,application/xhtml+xml,application/xml&lt;br /&gt;
attr WR_1_Speicher_1 get10Name Test_Array&lt;br /&gt;
attr WR_1_Speicher_1 get10URL http://%IP-WR_1_Speicher_1%/goform/SetRunData&lt;br /&gt;
attr WR_1_Speicher_1 getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1 handleRedirects 1&lt;br /&gt;
attr WR_1_Speicher_1 httpVersion 1.1&lt;br /&gt;
attr WR_1_Speicher_1 icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1 reAuthRegex Unauthorized&lt;br /&gt;
attr WR_1_Speicher_1 reading01Name auth_qop&lt;br /&gt;
attr WR_1_Speicher_1 reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Name auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Name auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Name auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Regex %IP-WR_1_Speicher_1%&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Value ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1_Speicher_1&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Regex %auth_realm%&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Value auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Regex %auth_nonce%&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Value auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Regex %auth_opaque%&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Value auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Regex %auth_response%&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Value {my $NAME=&amp;quot;WR_1_Speicher_1&amp;quot;;;my $pw=KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;);; $pw =~ &#039;&amp;quot;&#039;.s/@/\\@/g.&#039;&amp;quot;&#039;;; md5_hex(md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.$pw).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:00000001:d789ea5b7e9a2377:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;));;}&lt;br /&gt;
attr WR_1_Speicher_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1 showBody 0&lt;br /&gt;
attr WR_1_Speicher_1 showError 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid01ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sid02Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid02ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid02URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sortby 121&lt;br /&gt;
attr WR_1_Speicher_1 stateFormat {sprintf(&amp;quot;Total_Charge_Energy: %.0f kWh&amp;lt;br&amp;gt;Total_Efficiency: %.1f %% Battery_EM_State: %s&amp;quot;, ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Efficiency&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;Battery_EM_State&amp;quot;,&amp;quot;&amp;quot;))}&lt;br /&gt;
attr WR_1_Speicher_1 userReadings Statistic_SpecificInformation_00_Date:Statistic_SpecificInformation_05_EndTime.* { CommandDeleteReading(undef, $NAME.&amp;quot; .*-.*&amp;quot;);;;; localtime()},\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Difference_Charge_Energy:Statistic_GeneralInformation_Total_Charge_Energy.*  {ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Efficiency:Statistic_GeneralInformation_Total_Charge_Energy.*  {round(((ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)+((ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Act_state_of_charge&amp;quot;,0)/100)*11)) / ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0))*100 , 2)}&lt;br /&gt;
attr WR_1_Speicher_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1                    BYD HV     HTTPMOD   LAN/WLAN               Speicher Details, auch über einzelne Zellen. Das kann man nur für den alten BYD HV verwenden.&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Verwendet von Plenticore zur Steuerung des Speichers&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
PV_Schedule                                   DOIF                             Startet regelmäßige Aktionen&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Das ist veraltet, da die KI_Prognose nun verwendet werden sollte.&lt;br /&gt;
   2 Stündlich von 07:00 bis 20:00&lt;br /&gt;
   2.1 WR_1_config module_1_covered                                              Schnee auf den Modulen (noch in der Entwicklungsphase)&lt;br /&gt;
   2.2 Solar_forecast() für fc0                                                  Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 zweimal am Tag&lt;br /&gt;
   3.1 Solar_forecast() für fc1                                                  Aktualisieren der fc1 Prognose&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
   4 alle 5 Minuten&lt;br /&gt;
   4.1 WR_2_API 04_auth_me                                                       Aktualisieren der Bilanz (es wird ein Event erzeugt)&lt;br /&gt;
   4.2 WR_1_API 04_auth_me                                                       Der Master Wechselrichter kommt zum Schluss, damit die SW_* readings auch von anderen&lt;br /&gt;
                                                                                 Wechselrichtern die richtigen Werte haben.&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Dies ist jetzt im WR_ctl Device enthalten&lt;br /&gt;
WR_*_config                                   DUMMY                            Konfiguration für Strings,Ausrichtung,Nennleistung,IP-Adressen,Forecast&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC               begrenzt dann morgens den MaxSOC&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday     und den MaxChargePowerAbs&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning    für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_1:Solar_middayhigh_fc0_start &amp;lt;&amp;gt; WR_1:Solar_middayhigh_fc0_stop      Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_1:Solar_middayhigh_fc0_stop                         Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====SVG====&lt;br /&gt;
In eventuellen SVGs die Device und reading Namen korrigieren&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== AW Definition PV_Schedule (DOIF)===&lt;br /&gt;
Aufgrund der Komplexität wurde die Speichersteuerung aus diesem Device entfernt und im Device PV_1_Speicher_1_ExternControl ausgelagert.&lt;br /&gt;
Weitere Neuerungen sind die Bereitstellung eines Schnee Faktors pro String für die Solar_forecast() Funktion, was aber bitte als Versuch anzusehen ist.&lt;br /&gt;
Für den Vergleich mit dem Solar_Foracast Modul wird der Forecast zwei mal aufgerufen und einmal davon ins DWD_Forecast_Test geschrieben.&lt;br /&gt;
Diese Beispiele können natürlich einfach herausgelöscht werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
\&lt;br /&gt;
   (get WR_2_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
   (get WR_1_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 5 und 21 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([05:00-21:00] and [:00])\&lt;br /&gt;
   ## Erste Versuche mit Schnee, wenn zuwenig Strom in den Modulen fließt wird ein Faktor von 0.1 gesetzt\&lt;br /&gt;
   ## WR_1_config forecast_factor_autocorrection muss auf 1 gesetzt sein, damit das berücksichtigt wird\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt;  8 &amp;amp;&amp;amp; $hour &amp;lt; 12)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_1_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_2_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 12 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_3_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_4_covered &amp;quot;.$y)})\&lt;br /&gt;
\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   ## Bei Schnee wurde der module_*_covered Faktor bereits am Vortag gesetzt.\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 regelmäßig die Bilanz aktualisieren, alle 5 Minuten außer um :00\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00])\&lt;br /&gt;
\&lt;br /&gt;
  (get WR_2_API 04_auth_me)\&lt;br /&gt;
  (get WR_1_API 04_auth_me)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])   ## 6172\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])         ## 4727\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5707\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 4717\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5241\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 3517\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState WR Status|Forecast 0|Forecast 1|Bilanz refresh&lt;br /&gt;
attr PV_Schedule comment Version 2021.04.19 12:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0,3:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4&lt;br /&gt;
attr PV_Schedule webCmdLabel Statistic :Forecast_0 :Forecast_1 :Bilanz :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc.*_.*_Rad1h,fc.*_.*_TTT,fc.*_.*_FF,fc.*_.*_Neff,fc.*_.*_R101,fc.*_.*_RRS1c,fc.*_.*_DD,fc.*_.*_N,fc.*_.*_VV,fc.*_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2022.08.20 12:00\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
FF      : Windspeed\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc.*_.*_[Rad1h|TTT|FF|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,FF,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz,fc.*_.*&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro event-on-update-reading ObsDate.*,fc.*_.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
attr Astro userReadings fc0_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
\&lt;br /&gt;
fc1_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))}&lt;br /&gt;
attr Astro verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
CREATE DEFINER=`fhemuser`@`%` PROCEDURE `dwd_load`(IN var_date DATE, IN display char(10))&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;br /&gt;
SET @date:= var_date;&lt;br /&gt;
-- die alte Tabelle löschen&lt;br /&gt;
DROP TABLE IF EXISTS dwdfull;&lt;br /&gt;
&lt;br /&gt;
-- eine neue Tabelle anlegen&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `dwdfull` (&lt;br /&gt;
  `TIMESTAMP` datetime NOT NULL,&lt;br /&gt;
  `year`   int NOT NULL,&lt;br /&gt;
  `month`  int NOT NULL,&lt;br /&gt;
  `day`    int NOT NULL,&lt;br /&gt;
  `hour`   int NOT NULL,&lt;br /&gt;
  `TTT`    float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `DD`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `VV`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `N`      float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Neff`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `R101`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `RRS1c`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunD1`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Rad1h`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAz`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAlt` float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `yield`  float  DEFAULT 0,&lt;br /&gt;
  `yield_max`  float  DEFAULT 0,&lt;br /&gt;
  `forecast`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  PRIMARY KEY (`TIMESTAMP`),&lt;br /&gt;
  INDEX (`TIMESTAMP`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=&#039;DWD Forecast&#039;;&lt;br /&gt;
&lt;br /&gt;
-- als erstes die Grundlegenden Daten mit Zeitstempeln erzeugen&lt;br /&gt;
-- Rad1h wird als erstes eingetragen&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc0 Rad1h ältere Werte eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
	 	       )&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc1 Rad1h Werte von morgen eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Mit update alle weiteren Spalten füllen&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAz&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t2  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t2.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAz&lt;br /&gt;
  SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAlt&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t6 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t6.VV&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t5.VV&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t7 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t7.DD&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t5.DD&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t8 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t8.TTT&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t5.TTT&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t9 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t9.R101&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t5.R101&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t10 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t10.N&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t5.N&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t11 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t11.RRS1c&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t5.RRS1c&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield from Plenticore with Accu&lt;br /&gt;
   -- start left join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    left JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end left join&lt;br /&gt;
   &lt;br /&gt;
   UNION  -- for left and right join&lt;br /&gt;
&lt;br /&gt;
   -- start right join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    right JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end right join&lt;br /&gt;
   &lt;br /&gt;
   -- UNION end&lt;br /&gt;
   &lt;br /&gt;
  ) t12 USING(TIMESTAMP)&lt;br /&gt;
SET tt.yield = t12.yield&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Ermittle Ertrags Maximum der letzten 30 Tage um die Prognose zu limitieren&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield_max&lt;br /&gt;
      SELECT hour,&lt;br /&gt;
             cast(max(yield) AS DECIMAL(6)) AS yield_max&lt;br /&gt;
      FROM dwdfull&lt;br /&gt;
      WHERE TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
      GROUP BY hour&lt;br /&gt;
   ) t2  USING(hour)&lt;br /&gt;
SET tt.yield_max = t2.yield_max&lt;br /&gt;
WHERE TIMESTAMP &amp;gt; @date&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
IF display = &#039;show&#039; THEN &lt;br /&gt;
  select * from dwdfull LIMIT 3000;&lt;br /&gt;
ELSE&lt;br /&gt;
  select now();&lt;br /&gt;
END IF&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose (nicht mehr aktuell)==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
====Wetter Forecast Grundlagen (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der &lt;br /&gt;
    Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deutscher Wetter Dienst (DWD) (nicht mehr aktuell)===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
====RAW Definition DWD_Forecast (nicht mehr aktuell)====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wurden einige extra Werte vom DWD abgefragt, die für das Solar_Forecast Modul verwendet werden. Dieses Modul ist noch in der experimental Phase (2021.02.23) und liefert noch nicht gleichwertige Ergebnisse. Ein Test zum vergleichen kann aber nicht schaden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc0_.*_Rad1h,fc0_.*_TTT,fc0_.*_Neff,fc0_.*_R101,fc0_.*_RRS1c,fc0_.*_DD,fc0_.*_N,fc0_.*_VV,fc0_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2023.01.05 12:40\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc0_.*_[Rad1h|TTT|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===99_myUtils.pm Funktionen===&lt;br /&gt;
====Solar_forecast() (nicht mehr aktuell)====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen, muss ein Dummy WR_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Letzte Neuerungen:&lt;br /&gt;
- IM WR_1_config kann man verbose auf &amp;gt;3 setzen und bekommt dann Log Meldungen&lt;br /&gt;
- Es wird eine Autokorrektur unterstützt. Aktivierung durch &amp;quot;setreading WR_1_config forecast_factor_autocorrection 1&amp;quot;&lt;br /&gt;
  Für die Datenbank Anbindung wird ein DbRep Device LogDBRep_PV_Forecast_SQL verwendet. Die RAW definition kommt gleich im Anschluss.&lt;br /&gt;
- Das SQL für die Berechnung des Faktors der Autokorrektur Verwendet Konfigurationsvariablen aus den DbRep Device.&lt;br /&gt;
- Bei der Autokorrektur wird auch eine Bedeckung von Schnee (Strom im String &amp;lt; 1A) berücksichtigt. (das ist noch in der Entwicklung)&lt;br /&gt;
  Dieser Faktor wird im PV_Schedule Device erzeugt und dann im &amp;quot;WR_1_config module_*_covered&amp;quot; für jeden String eingetragen.&lt;br /&gt;
  Das muss jeder individuell für seine Anlage anpassen!&lt;br /&gt;
- Für die 70% Regelung wird nun auch ein Middayhigh Trigger ermittelt und die jeweilige Start/Stop Zeit. Dies steht dann im WR_1 Device bei den Solar_* readings&lt;br /&gt;
- Es besteht auch die Möglichkeit die Solar_forecast() Funktion ohne Datenbank zu verwenden, dann ist bei den Parametern &amp;quot;none&amp;quot; zu übergeben und&lt;br /&gt;
  es muss auch die Autokorrektur abgeschaltet sein.&lt;br /&gt;
- Anstelle des Wechselrichter Devices kann nun auch ein beliebiges anderes Device angegeben werden, in das dann der Forecast geschrieben wird.&lt;br /&gt;
  Auch hier kann dann keine Autokorrektur verwendet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.06.14 15:20&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;        # Mit dieser Datenbank wird gearbeitet&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zur Kommunikation mit der LogDB verwendet und muss entsprechend konfiguriert sein&lt;br /&gt;
     my $logdevice   = &amp;quot; &amp;quot;   ;        # Das ist der Wechselrichter, oder ein anderes Device, in das die Prognose geschrieben wird&lt;br /&gt;
        $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;    # Der reading Name wird um 0 oder 1 verlängert&lt;br /&gt;
&lt;br /&gt;
     # Welcher Verbose Level ist gesetzt?&lt;br /&gt;
     my $verbose = AttrVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Gibt es einen festen Korrekturfaktor für jede Stunde?&lt;br /&gt;
     my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
     # Soll eine Autokorrektur gemacht werden? 0 = Nein 1 = Ja&lt;br /&gt;
     my $autocorrection          = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor_autocorrection&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Beim DWD wird der Wert für die Stunde erst am Ende der Stunde eingetragen&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     # Hier werden die Variablen vorbelegt&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry1h,$logentry4h,$logentryrest,$logentry,$i) = (0) x 9 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($module_covered,$Solar_Correction_Faktor_auto,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 6 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 06:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $logdbrep ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
       # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
       CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Setzen der Tageszähler und Merker&lt;br /&gt;
     $logentry            = 0 ;   # Summiert den Solar_Calculation Wert für den ganzen Tag&lt;br /&gt;
     $logentry4h          = 0 ;   # Summierung für die nächsten vier Stunden&lt;br /&gt;
     $logentryrest        = 0 ;   # Summierung für den Rest des Tages&lt;br /&gt;
&lt;br /&gt;
     my $middayhigh           = 0 ; # Ein Merker, ob das Tagesmaximum überschritten wird&lt;br /&gt;
     my $middayhigh_start     = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_stop      = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_tmp       = 0;&lt;br /&gt;
     my $middayhigh_start_tmp = 0;&lt;br /&gt;
     my $middayhigh_stop_tmp  = 0;&lt;br /&gt;
&lt;br /&gt;
     my $Inverter_Max_Power = ReadingsVal($logdevice.&amp;quot;_Speicher_1_ExternControl&amp;quot;,&amp;quot;SpeicherMidday_Inverter_Max_Power&amp;quot;,&amp;quot;unused&amp;quot;);  # Überschreiben des middayhigh&lt;br /&gt;
     if ($Inverter_Max_Power eq &amp;quot;unused&amp;quot;) {&lt;br /&gt;
       $Inverter_Max_Power = ReadingsVal($logdevice,&amp;quot;Inverter_Max_Power&amp;quot;,0) +500 ;      # Hier wird ein Durchschnittsverbrauch des Hauses aufaddiert&lt;br /&gt;
     } else {&lt;br /&gt;
       if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power manuell gesetzt&amp;quot; } ;&lt;br /&gt;
     };&lt;br /&gt;
     if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power auf &amp;quot;.$Inverter_Max_Power.&amp;quot; gesetzt&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
     # Es werden Stundenwerte von 06:00 bis 21:00 Uhr berechnet&lt;br /&gt;
     for ($i = 6; $i &amp;lt;= 21; $i++) {&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0 and $i == 6) {&lt;br /&gt;
         # Neuberechnung der stündlichen Autokorrektur Faktoren in der Datenbank. Das DbRep Device LogDBRep_PV_Forecast_SQL muss vorhanden sein.&lt;br /&gt;
         # Achtung, beim SQL muss &#039;@&#039; mit &#039;\@&#039; maskiert werden.&lt;br /&gt;
         CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking &amp;quot;.sprintf(&amp;quot;&lt;br /&gt;
               INSERT INTO history&lt;br /&gt;
                 (TIMESTAMP,DEVICE,READING,VALUE)&lt;br /&gt;
                  SELECT&lt;br /&gt;
                    TIMESTAMP,DEVICE,READING,VALUE&lt;br /&gt;
                  FROM (&lt;br /&gt;
                    SELECT&lt;br /&gt;
                      DATE_ADD(CURDATE(),INTERVAL t2.HOUR HOUR) AS TIMESTAMP,&lt;br /&gt;
                      t2.DEVICE,&lt;br /&gt;
                      \@readingname                             AS READING,&lt;br /&gt;
                      cast(if(avg(t2.FACTOR) &amp;gt; 1.6, 1.6,&lt;br /&gt;
                              avg(t2.FACTOR) ) AS DECIMAL(2,1)) AS VALUE&lt;br /&gt;
                    FROM (&lt;br /&gt;
                      SELECT * FROM (&lt;br /&gt;
                        SELECT&lt;br /&gt;
                          t1.TIMESTAMP,&lt;br /&gt;
                          t1.HOUR,&lt;br /&gt;
                          t1.DEVICE,&lt;br /&gt;
                          t1.READING,&lt;br /&gt;
                          t1.VALUE,&lt;br /&gt;
                          if(\@diff = 0,0, \@temp:=cast((t1.VALUE-\@diff) AS DECIMAL(8,2)))                                    AS DIFF,&lt;br /&gt;
                          if(((t1.VALUE+(-1*\@temp))*\@corr)=0,0, cast((t1.VALUE/(t1.VALUE+(-1*\@temp))*\@corr) AS DECIMAL(8,1))) AS FACTOR,&lt;br /&gt;
                          \@diff:=t1.VALUE                                                                                        AS curr_V&lt;br /&gt;
                        FROM (&lt;br /&gt;
                          SELECT&lt;br /&gt;
                            h.TIMESTAMP,&lt;br /&gt;
                            date(h.TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(h.TIMESTAMP) AS HOUR,&lt;br /&gt;
                            h.DEVICE,&lt;br /&gt;
                            h.READING,&lt;br /&gt;
                            h.VALUE&lt;br /&gt;
                          FROM history AS h&lt;br /&gt;
                          WHERE h.DEVICE    =  \@device&lt;br /&gt;
                            AND (h.READING  =  \@reading1 OR h.READING = \@reading2)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;gt;= DATE_SUB(DATE(now()),INTERVAL \@days DAY)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;lt;= CURDATE()&lt;br /&gt;
                            AND MINUTE(h.TIMESTAMP) = 0&lt;br /&gt;
                            AND h.VALUE &amp;gt;= 50&lt;br /&gt;
                          GROUP BY DATE,HOUR,h.READING,h.DEVICE,h.TIMESTAMP&lt;br /&gt;
                         )t1&lt;br /&gt;
                       )tx&lt;br /&gt;
                        WHERE READING != \@reading2&lt;br /&gt;
                          AND HOUR &amp;gt; 6&lt;br /&gt;
                     )t2&lt;br /&gt;
                      GROUP BY t2.HOUR,t2.DEVICE&lt;br /&gt;
                   )t3&lt;br /&gt;
                    WHERE&lt;br /&gt;
                      t3.VALUE != 0&lt;br /&gt;
                    ORDER BY TIMESTAMP&lt;br /&gt;
                    ON DUPLICATE KEY UPDATE&lt;br /&gt;
                      VALUE=t3.VALUE;&lt;br /&gt;
           &amp;quot;) # Ende sprintf()&lt;br /&gt;
         );   # Ende CommandGet()&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
       $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
       if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
         $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
&lt;br /&gt;
         $Solar_Rain = 0;&lt;br /&gt;
         for (my $r600 = $i+5; $r600 &amp;gt;= $i; $r600--) {&lt;br /&gt;
           $Solar_Rain        += ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($r600+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
         $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
         $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
         $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
         if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation.&amp;quot; W &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0).&amp;quot; J&amp;quot; } ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($cloudk ne 0) {&lt;br /&gt;
         $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
         $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($raink ne 0) {&lt;br /&gt;
         $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($tempk ne 0) {&lt;br /&gt;
         $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0) {&lt;br /&gt;
         $Solar_Correction_Faktor_auto = CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking SELECT VALUE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;Solar_Correction_Faktor_auto&#039; AND TIMESTAMP=&#039;&amp;quot;.sprintf(&amp;quot;%4d-%02d-%02d %02d:00:00&amp;quot;,$year,$mon,$mday,$i).&amp;quot;&#039;;&amp;quot;) ;&lt;br /&gt;
         if($Solar_Correction_Faktor_auto eq &amp;quot;&amp;quot;) { $Solar_Correction_Faktor_auto = 1; };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $logentry1h = 0 ;   # Summierung für eine Stunde zurücksetzen&lt;br /&gt;
&lt;br /&gt;
       # Es werden 5 Modul Ausrichtungen durchlaufen, der Name der Ausrichtung befindet sich z.B. in WR_1_config&lt;br /&gt;
       for(my $j=1;$j&amp;lt;=5;$j++){&lt;br /&gt;
         # lesen der Modul Anzahl&lt;br /&gt;
         $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
         if ($module_count[$j] ne 0) {&lt;br /&gt;
           # Für diese Ausrichtung sind Module Installiert&lt;br /&gt;
&lt;br /&gt;
           # Berechnung des Korrekturfaktors für die Modul Ausrichtung&lt;br /&gt;
           $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;factor/plain/direction       : &amp;quot;.$Solar_Plain.&amp;quot; &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) };&lt;br /&gt;
           # Berechnung der Modul Nennleistung für diese Ausrichtung&lt;br /&gt;
           $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
           # Anwendung der Korrekturfaktoren&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp   * $Solar_Correction_Cloud * $Solar_Correction_Rain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Faktor ;&lt;br /&gt;
&lt;br /&gt;
           if ($autocorrection ne 0) {&lt;br /&gt;
             # Nachsehen, ob dieser String mit Schnee bedeckt ist&lt;br /&gt;
             $module_covered = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_covered&amp;quot;,1) ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $Solar_Correction_Faktor_auto ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $module_covered ;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot;_covered             : &amp;quot;.$module_covered };&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Runden auf volle Watt Werte&lt;br /&gt;
           $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot; estimation          : &amp;quot;.$Solar_[$j] };&lt;br /&gt;
&lt;br /&gt;
           # Aufsummieren aller konfigurierter Ausrichtungen&lt;br /&gt;
           $logentry1h += $Solar_[$j] ; # Summe für eine Stunde (wird mit jedem lauf von $i wieder auf 0 gesetzt)&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe der nächsten 4 h gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour and $i &amp;lt;= $hour+3) {&lt;br /&gt;
             $logentry4h += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe für den Resttag gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour) {&lt;br /&gt;
             $logentryrest += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           $logentry += $Solar_[$j] ; # Summe für den ganzen Tag&lt;br /&gt;
&lt;br /&gt;
           # Den Forecast Wert für die aktuelle Stunde in das Wechselrichter Device schreiben&lt;br /&gt;
           if ($fc == 0 and $hour == $i) {&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;                   : &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; };&lt;br /&gt;
             CommandSetReading(undef, $logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j]) ;&lt;br /&gt;
           };&lt;br /&gt;
         };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Alle Forecast Werte für die jeweilige Stunde in die DbLog schreiben (Es wird der Cache verwendet)&lt;br /&gt;
&lt;br /&gt;
       if ( $logdb ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
         CommandSet(undef, $logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry1h.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry1h.&amp;quot;|&amp;quot;) ;&lt;br /&gt;
&lt;br /&gt;
         if ( $middayhigh == 0 and $logentry1h &amp;gt; $Inverter_Max_Power ) {&lt;br /&gt;
           $middayhigh           = 1;&lt;br /&gt;
           $middayhigh_start_tmp = $i-1;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;lt; $Inverter_Max_Power and $middayhigh_stop_tmp == 0 )  {&lt;br /&gt;
           $middayhigh_stop_tmp = $i;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;gt; $Inverter_Max_Power and $middayhigh_stop ne &amp;quot;00:00&amp;quot; )  {&lt;br /&gt;
           $middayhigh_stop_tmp = 0;                                # da war ein kurzer Einbruch, es sollte noch länger sein.&lt;br /&gt;
         };&lt;br /&gt;
         if ($middayhigh == 1 and&lt;br /&gt;
             $middayhigh_stop_tmp != 0 and&lt;br /&gt;
             $middayhigh_stop_tmp == $i ) {                                    # das Ende des Middayhigh wurde gefunden&lt;br /&gt;
&lt;br /&gt;
           $middayhigh_tmp = $middayhigh_stop_tmp - $middayhigh_start_tmp;&lt;br /&gt;
           if ( $middayhigh_tmp &amp;gt; 4 )  {                                       # das Middayhigh wird zu lang&lt;br /&gt;
             if ($verbose &amp;gt;= 3 ) {                                             # die bisherigen Zeiten ausgeben&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp) ;&lt;br /&gt;
             }&lt;br /&gt;
             $middayhigh_tmp       = round(($middayhigh_tmp/4)-0.2 ,0);        # die Rundung der Zeit zum Abziehen etwas verschieben&lt;br /&gt;
             $middayhigh_start_tmp = $middayhigh_start_tmp + $middayhigh_tmp;  # es wird um ganze Stunden verkürzt&lt;br /&gt;
             $middayhigh_stop_tmp  = $middayhigh_stop_tmp  - $middayhigh_tmp;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) {                                              # melde die Verkürzung&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;         : verkürzt um &amp;quot;.($middayhigh_tmp *2).&amp;quot; Stunden&amp;quot;;&lt;br /&gt;
             }&lt;br /&gt;
           };&lt;br /&gt;
           $middayhigh_start = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
           $middayhigh_stop  = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp);&lt;br /&gt;
           if ($verbose &amp;gt;= 3) {                                                # gib die finalen Zeiten aus&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.$middayhigh_start;&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.$middayhigh_stop ;&lt;br /&gt;
           }&lt;br /&gt;
         };&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ; # setz die Zeiten im Device&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Sobald mindestens ein String configuriert ist sollen diese Werte, der aktuellen Stunde, in das Wechselrichter Device geschrieben werden&lt;br /&gt;
       if ($fc == 0 and $hour == $i and $module_count[1] ne 0) {&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry1h) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Auch die Solar_Calculation jeder einzelnen Stunde wird als reading in das Wechselrichter Device geschrieben&lt;br /&gt;
       CommandSetReading(undef, sprintf(&amp;quot;%s %s_%02d %d&amp;quot;,$logdevice,$reading,$i,$logentry1h)) ;&lt;br /&gt;
&lt;br /&gt;
       # Für die Fehlersuche kommen noch einige Informationen ins Log&lt;br /&gt;
       if ($verbose &amp;gt;= 3) {&lt;br /&gt;
         Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Cloud                  : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;cloudk                       : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Cloud       : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Rain                   : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;raink                        : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Rain        : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Temp                   : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;tempk                        : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Temp        : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor      : &amp;quot;.$Solar_Correction_Faktor ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor_auto : &amp;quot;.$Solar_Correction_Faktor_auto ;&lt;br /&gt;
         Log 3, &amp;quot;Forecast,Hour,Estimation 1h  : &amp;quot;.$fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$logentry1h ;&lt;br /&gt;
       };&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Die Summe der nächsten 4 Stunden in das Wechselrichter Device schreiben&lt;br /&gt;
     if ($fc == 0) {&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_4h &amp;quot;.$logentry4h) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_rest &amp;quot;.$logentryrest) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_day &amp;quot;.$logentry) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $middayhigh == 0 ) {    # Auf Defaults zurücksetzen&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.02.28 17:00&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    my $verbose     = AttrVal(&amp;quot;Astro&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = CommandGet(undef, &amp;quot;Astro text SunAz &amp;quot;.$time) ;&lt;br /&gt;
    my $elevation   = CommandGet(undef, &amp;quot;Astro text SunAlt &amp;quot;.$time) ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain time             : &amp;quot;.$time;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain azimuth          : &amp;quot;.$azimuth;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain elevation        : &amp;quot;.$elevation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain orientation      : &amp;quot;.$orientation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain angle            : &amp;quot;.$angle;&lt;br /&gt;
    };&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.1798) {&lt;br /&gt;
      if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_Forecast_SQL (nicht mehr aktuell)====&lt;br /&gt;
Dieses Device war vormals das LogDBRep_PV_Forecast_SQL , es wird jedoch nun mehrfach verwendet und wurde deshalb umbenannt. Das LogDBRep_PV_Forecast_SQL kann gelöscht werden.&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
Für die Solar_forecast() Funktion wurden hier SQL Variablen Definiert, die für die Autokorrektur verwendet werden:&lt;br /&gt;
- @days ist die Anzahl der Tage, über die ein stündlicher, durchschnitts Korrektur Faktor berechnet wird.&lt;br /&gt;
- @corr ermöglicht es diesen Faktor nochmals zu verändern &amp;lt;1 dämpft, &amp;gt;1 verstärkt&lt;br /&gt;
- @device ist der Plenticore Wechselrichter&lt;br /&gt;
- @reading1 ist die reale DC Leistung ohne die Batterie, hier wird &#039;&#039;&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;&#039;&#039; für die Schwarm Implementierung verwendet.&lt;br /&gt;
- @reading2 wird der Basisname der readings im WR_1 Device&lt;br /&gt;
- @readingname wird der reading Name des Korrekturfaktors.&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
Durch die Erweiterung zum Schwarm mit mehreren AC-Quellen wurde die Variable @reading1 verändert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_Forecast_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL allowDeletion 1&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL room System&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdVars SET @days:=3, @corr:=0.7, @diff:=0, @temp:=0, @device:=&#039;WR_1&#039;, @reading1:=&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;, @reading2:=&#039;Solar_Calculation_fc0&#039;, @readingname:=&#039;Solar_Correction_Faktor_auto&#039; ;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solar Forcast Tests (nicht mehr aktuell)===&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Astro Device Test====&lt;br /&gt;
Bei diesem Test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() Test (nicht mehr aktuell)====&lt;br /&gt;
Diese Funktion kann man folgendermaßen testen. Für Log Meldungen muss man im &#039;&#039;&#039;Astro Device verbose auf 3&#039;&#039;&#039; oder größer stellen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung, das Dach hätte demnach also Süd/West Lage.&lt;br /&gt;
&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann Folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:51:27.312 3: Solar_plain azimuth          : 210.6&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain elevation        : 0.49916224518291&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain orientation      : 0.185004188774085&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain angle            : 0.785395141022061&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain factor           : 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurückgeliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_forecast() Test (nicht mehr aktuell)====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
Bei gesetztem &amp;quot;&#039;&#039;&#039;attr Astro verbose 3&#039;&#039;&#039;&amp;quot; erscheinen hier ebenfalls die Astro Log Informationen.&lt;br /&gt;
Durch setzen von &amp;quot;&#039;&#039;&#039;attr WR_1_config verbose 3&#039;&#039;&#039;&amp;quot; bekommt man die Log Meldungen vom Sorar_forecast()&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&lt;br /&gt;
generische Verwendung ohne DbLog/DbRep: &#039;&#039;&#039;Das Astro Device muss &amp;quot;Astro&amp;quot; heißen und das DWD Device muss &amp;quot;DWD_Forecast&amp;quot; heißen!!&#039;&#039;&#039;&lt;br /&gt;
{Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;&amp;lt;beliebiges Device&amp;gt;&amp;quot;,&amp;quot;&amp;lt;prefix für die readings&amp;gt;_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,[0|1])}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann solche Blöcke, die man zusammenhängend betrachten sollte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power manuell gesetzt&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power auf 7000 gesetzt&lt;br /&gt;
2021.04.07 15:57:23.932 3: Solar_SolarRadiation         : 17 W 60.00 J        &amp;lt;&amp;lt;&amp;lt; vom DWD gelieferte Prognose in Watt und Joul&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain azimuth          : 80.2                &amp;lt;&amp;lt;&amp;lt; Astro Informationen&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain orientation      : -0.171041608489249&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain factor           : 0.001               &amp;lt;&amp;lt;&amp;lt; Die Funktion ist noch außerhalb des Gültigkeitsbereiches&lt;br /&gt;
2021.04.07 15:57:23.977 3: factor/plain/direction       : 0.001 40/-90     &lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1_covered             : 1                   &amp;lt;&amp;lt;&amp;lt; Ein Faktor für die Schneebedeckung&lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1 estimation          : 0                   &amp;lt;&amp;lt;&amp;lt; Die erwartete Leistung liegt bei 0 Watt&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:23.991 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2_covered             : 1&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain orientation      : -1.94183189053337&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.002 3: factor/plain/direction       : 0.001 40/0&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.013 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.020 3: Solar_SolarRadiation         : 17                  &amp;lt;&amp;lt;&amp;lt; Rad1h ist 70 Watt&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Cloud                  : 70                  &amp;lt;&amp;lt;&amp;lt; 70 % Abdeckung des Himmels durch Wolken&lt;br /&gt;
2021.04.07 15:57:24.021 3: cloudk                       : -0.45 0             &amp;lt;&amp;lt;&amp;lt; Werte der Korrekturfunktion für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Correction_Cloud       : 0.685               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Rain                   : 152&lt;br /&gt;
2021.04.07 15:57:24.022 3: raink                        : -0.2 0&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Correction_Rain        : 0.696               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Regen&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Temp                   : 10.7                &amp;lt;&amp;lt;&amp;lt; Erwartete Temperatur an den Modulen (Schätzung) &lt;br /&gt;
2021.04.07 15:57:24.023 3: tempk                        : -0.39 25&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Temp        : 1.056               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für die Modultemperatur&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor      : 1                   &amp;lt;&amp;lt;&amp;lt; Fester Korrekturfaktor aus WR_1_config &lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor_auto : 0.5                 &amp;lt;&amp;lt;&amp;lt; Korrekturfaktor aus der Datenbank Berechnung der letzten Tage &lt;br /&gt;
2021.04.07 15:57:24.024 3: Forecast,Hour,Estimation 1h  : 0 7 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Forecast Basiseinstellung (nicht mehr aktuell)===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät WR_1_config von einer Ost/Süd/West Anlage mitgeliefert (setstate). Es werden bis zu 5 Strings unterstützt.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auch &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät WR_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch zusätzliche Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Berücksichtigung von Temperatur, Bewölkung und Regen (nicht mehr aktuell)===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das Ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
Durch die Autokorrektur ist nun auch ein Schnee Faktor dazu gekommen. Dieser wird im PV_Schedule Device &amp;quot;berechnet&amp;quot; :-) und und in das PV_1_config geschrieben. Bei aktivierter Autokorrektur wird dieser dann berücksichtigt.&lt;br /&gt;
=====Temperatur (nicht mehr aktuell)=====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Wolken und Regen (nicht mehr aktuell)=====&lt;br /&gt;
Aus den DWD_Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken Einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
===wunderground===&lt;br /&gt;
Dieser Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das kann dann als aktueller Wert in den Diagrammen angezeigt werden und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mit einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
&lt;br /&gt;
===RAW Definition Wetter_&amp;lt;Wohnort&amp;gt;===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;JSON&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;builtIn&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;datasource&amp;quot;: &amp;quot;-- Grafana --&amp;quot;,&lt;br /&gt;
        &amp;quot;enable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;iconColor&amp;quot;: &amp;quot;rgba(0, 211, 255, 1)&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Annotations &amp;amp; Alerts&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;dashboard&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;editable&amp;quot;: true,&lt;br /&gt;
  &amp;quot;gnetId&amp;quot;: null,&lt;br /&gt;
  &amp;quot;graphTooltip&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;id&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;links&amp;quot;: [],&lt;br /&gt;
  &amp;quot;panels&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P value&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;: &amp;quot;rgb(90, 90, 90)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid value&amp;quot;: &amp;quot;rgb(250, 250, 250)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_AC_Active_P&amp;quot;: &amp;quot;dark-orange&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P&amp;quot;: &amp;quot;semi-dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 0&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: false,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:78&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:79&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:80&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 10,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:81&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:82&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:83&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 5,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS &#039;SW_Total_DC_P&#039;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_grid\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_grid&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_PV\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_PV&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_Battery\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_Battery&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Actual_Battery_charge_usable_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Actual_Battery_charge_usable_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_AC_Active_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_AC_Active_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;A&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Leistungsbezug&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Heizung&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Heizung value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Pool&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Waschmaschine&amp;quot;: &amp;quot;light-red&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 12&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hideEmpty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;hideZero&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: true,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;connected&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true,&lt;br /&gt;
          &amp;quot;steppedLine&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P_Max&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  abs(avg(value)) AS \&amp;quot;Heizung\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;StromZaehler_Heizung&#039; AND\n  READING = &#039;SMAEM1901401955_Saldo_Wirkleistung&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;StromZaehler_Heizung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SMAEM1901401955_Saldo_Wirkleistung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Pool\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly02&#039; AND\n  READING = &#039;Power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly02&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Waschmaschine\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly03&#039; AND\n  READING = &#039;power&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly03&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Brunnen\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Brunnen&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Shaun\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_1&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Shaun&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hauptverbraucher&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0&amp;quot;: &amp;quot;super-light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0 value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1 value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East value&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South value&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West&amp;quot;: &amp;quot;light-purple&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West value&amp;quot;: &amp;quot;super-light-purple&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 13,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 24&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: null,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc0\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc0&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc1\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc1&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc1&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_sumOfAllPVInputs\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_sumOfAllPVInputs&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_DC_Sum&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Solar_Calculation\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_Ost\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_Ost&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_Ost&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_Ost&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_Sued\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_Sued&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_Sued&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_Sued&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Forecast/Prognose&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;16000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;refresh&amp;quot;: &amp;quot;5m&amp;quot;,&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 27,&lt;br /&gt;
  &amp;quot;style&amp;quot;: &amp;quot;dark&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [],&lt;br /&gt;
  &amp;quot;templating&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: []&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;time&amp;quot;: {&lt;br /&gt;
    &amp;quot;from&amp;quot;: &amp;quot;now-1d/d&amp;quot;,&lt;br /&gt;
    &amp;quot;to&amp;quot;: &amp;quot;now-1d/d&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timepicker&amp;quot;: {&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;refresh_intervals&amp;quot;: [&lt;br /&gt;
      &amp;quot;5s&amp;quot;,&lt;br /&gt;
      &amp;quot;10s&amp;quot;,&lt;br /&gt;
      &amp;quot;30s&amp;quot;,&lt;br /&gt;
      &amp;quot;1m&amp;quot;,&lt;br /&gt;
      &amp;quot;5m&amp;quot;,&lt;br /&gt;
      &amp;quot;15m&amp;quot;,&lt;br /&gt;
      &amp;quot;30m&amp;quot;,&lt;br /&gt;
      &amp;quot;1h&amp;quot;,&lt;br /&gt;
      &amp;quot;2h&amp;quot;,&lt;br /&gt;
      &amp;quot;1d&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timezone&amp;quot;: &amp;quot;utc&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;PV_Anlage_1&amp;quot;,&lt;br /&gt;
  &amp;quot;uid&amp;quot;: &amp;quot;W-Y51Dmgk&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: 105&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit SVG==&lt;br /&gt;
Die Diagramme werden bei mir nicht mehr weiterentwickelt, da ich auf Grafana umgestiegen bin. Sie stehen hier nur noch als Beispiele für den Anfang.&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Total_PV_P_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_Battery::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB WR_1:SW_Actual_battery_charge_usable_P::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_Max::&lt;br /&gt;
#LogDB WR_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:max_month_SW_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_&amp;lt;Wohnort&amp;gt;_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB WR_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_sumOfAllPVInputs::&lt;br /&gt;
#LogDB WR_1:Solar_Calculation::&lt;br /&gt;
#LogDB WR_1:Solar_East::&lt;br /&gt;
#LogDB WR_1:Solar_South::&lt;br /&gt;
#LogDB WR_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power_(sumOfAllPVInputs)&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV_Perl (DOIF Modul) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 1                                   ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                     ## Die LWP ist aus\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]           ## Die maximale Laufzeit der LWP ist noch nicht erreicht\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## Das Maximum des PV-Modus ist noch nicht erreicht\&lt;br /&gt;
     and [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]   ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : LWP on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;LWP_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;PV_Modus_Ein_LWP();;set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;)&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : LWP on for manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : LWP off after manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]          ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : LWP off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; 100                              ## es soll noch eine Reserve bleiben\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : LWP off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;gt; 0                                  ## läuft eine Wartezeit\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 5                                  ## läuft die Wartezeit bald ab\&lt;br /&gt;
     and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot;\&lt;br /&gt;
      and [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe läuft&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer LWP &amp;quot;.get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;)};;\&lt;br /&gt;
    del_Exec(&amp;quot;LWP_Ein_timer&amp;quot;);;                                           ## Die LWP wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
## Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_1_LWP_Nachheizen_WW\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [[$SELF:TimeEnd]]                                               ## Am Ende der möglichen PV Steuerung\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt;= 48                             ## wenn das Wasser noch nicht im Sollbereich ist\&lt;br /&gt;
     and\&lt;br /&gt;
        (   [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]        ## Die maximale Laufzeit der LWP/Tag ist noch nicht erreicht\&lt;br /&gt;
         or [LWP_Counter:countsPerDay] eq 0)                             ## oder die LWP ist noch gar nicht gelaufen\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_LWP_Nachheizen_WW&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP on for water heating&amp;quot;};;\&lt;br /&gt;
                                                                         ## Es wird die Soll Temperatur um die Hysterese angehoben \&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget &amp;quot;.(ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,48)+4));;\&lt;br /&gt;
                                                                         ## Das zurücksetzen auf den Standard von 50° erfolgt generell beim Abschalten\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Hohe Priorität im Winter für die LWP\&lt;br /&gt;
## Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_2_LWP_Prioritaet_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [WR_1:SW_Total_PV_P_reserve] &amp;gt;= 2000                            ## es besteht jedoch noch eine Reserve und der\&lt;br /&gt;
     and [shelly02:power_0] &amp;gt; 800                                        ## Pool wird gerade aufgeheizt, was im Winter auch in der Nacht passiert\&lt;br /&gt;
     and [WR_1:Act_state_of_charge] &amp;gt; 60                                 ## Der Speicher sollte schon 60 % gefüllt sein\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## und die WW Temperatur noch unter 60°\&lt;br /&gt;
     and [$SELF:LWP_Priority] eq &amp;quot;frei&amp;quot;                                  ## Aber nur einmal am Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_LWP_Prioritaet_An&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_2 : LWP Priorität&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___LWP_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
        or [$SELF:LWP_Status] eq &amp;quot;manuell&amp;quot;\&lt;br /&gt;
       )\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimeMin]\&lt;br /&gt;
     and ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___LWP_Ende&amp;quot;                           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 05__ : LWP run finished&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Priorität für LWP wieder frei geben, damit einmal am Tag der PV-Modus verwendet werden kann\&lt;br /&gt;
##\&lt;br /&gt;
06___LWP_Prioritaet_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [23:55]\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;06___LWP_Prioritaet_Reset&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 06__ : LWP Priorität frei&amp;quot;};;\&lt;br /&gt;
     set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;frei&amp;quot;);;                                 ## Der PV-Modus darf wieder verwendet weden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## In der Überganszeit wird die Heizung kurz vor der PV-Zeit wieder ein geschaltet\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_1_Heizung_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeStartHeizung]]                                        ## Einschalten der Heizung, damit aus dem Puffer nachgeheizt wird 02:03\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_1_Heizung_An&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_1 : LWP Heizung Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHeating Auto&amp;quot;);;                  ## Die Heizungssteuerung erfolgt wieder Automatisch\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_2_Heizung_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeEndHeizung]]                                          ## Abschalten der Heizung, damit der Puffer für morgens Heizreserve hat\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_2_Heizung_Aus&amp;quot;                        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 07_2 : LWP Heizung aus&amp;quot;};;\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;Heizung opModeHeating Off&amp;quot;);;                     ## Die Heizung wird komplett abgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
   if (    [WR_1:Solar_Calculation_fc1_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] ## Auch morgen ist das Wetter schlecht\&lt;br /&gt;
       and [Heizung:averageAmbientTemperature] &amp;lt;= 5.6 ) {                ## Die Heizgrenze ist schon ziemlich tief\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungWinter]);;    ## Im Winter bis in die Morgenstunden den Accu sparen\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 07_2 : Parameter: &amp;quot;.[WR_1:Solar_Calculation_fc1_day].&amp;quot; &amp;lt; &amp;quot;.[WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit].&amp;quot; and &amp;quot;.[Heizung:averageAmbientTemperature].&amp;quot; &amp;lt;= 5.6&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungUebergang]);; ## Bei schönerem Wetter erst später Heizen\&lt;br /&gt;
     }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_2 : TimeStartHeizung switched to &amp;quot;.[$SELF:TimeStartHeizung]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 15°\&lt;br /&gt;
##\&lt;br /&gt;
07_3_Heizung_WZ_15_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_3_Heizung_WZ_15_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_3 : Heizung WZ 15 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 15&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 22°\&lt;br /&gt;
##\&lt;br /&gt;
07_4_Heizung_WZ_22_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_4_Heizung_WZ_22_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_4 : Heizung WZ 22 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 22&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung aus\&lt;br /&gt;
##\&lt;br /&gt;
07_5_Warmwasser_aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_5_Warmwasser_aus&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_5 : LWP Warmwasser aus&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Off&amp;quot;);;                  ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation inactive&amp;quot;);;                      ## Zirkulation ebenfalls abschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung auf Automatik\&lt;br /&gt;
##\&lt;br /&gt;
07_6_Warmwasser_an\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_6_Warmwasser_an&amp;quot;                      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_6 : LWP Warmwasser Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Auto&amp;quot;);;                 ## Die Warmwassersteuerung erfolgt wieder automatisch\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation active&amp;quot;);;                        ## Zirkulation wieder einschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_LWP() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP on&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 60.0&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;verwendet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_LWP() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 50.0&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr LWP_PV_Perl DbLogExclude .*&lt;br /&gt;
attr LWP_PV_Perl DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV_Perl alias LWP_PV_Perl&lt;br /&gt;
attr LWP_PV_Perl comment Version 2023.01.18 09:00&lt;br /&gt;
attr LWP_PV_Perl disable 0&lt;br /&gt;
attr LWP_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV_Perl icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV_Perl room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV_Perl sortby 411&lt;br /&gt;
attr LWP_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|::ReadingsTimestamp(&amp;quot;Heizung&amp;quot;,&amp;quot;counterHeatQTotal&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Status / LWP Status / Brauchwasser&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,04_1_LWP_Nachheizen_WW,04_2_LWP_Prioritaet_An,05___LWP_Ende,06___LWP_Prioritaet_Reset,07_1_Heizung_An,07_2_Heizung_Aus,07_3_Heizung_WZ_15_Grad,07_4_Heizung_WZ_22_Grad,07_5_Warmwasser_aus,07_6_Warmwasser_an&amp;quot;) |[Heizung:opStateHeatPump1].&amp;quot; &amp;quot;.[Heizung:opStateHeatPump2]|[Heizung:opStateHeatPump3]|FUNC_Status([Heizung:hotWaterTemperature],47,&amp;quot;orange&amp;quot;,[Heizung:hotWaterTemperature],&amp;quot;green&amp;quot;,[Heizung:hotWaterTemperature],53,&amp;quot;red&amp;quot;,[Heizung:hotWaterTemperature]).&amp;quot; °C&amp;quot;\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;PV-Modus / Heiz-Modus / Winter, Übergangszeit Heiz Start/Ende&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;PV-Modus:&amp;lt;br&amp;gt;&amp;quot;.[$SELF:LWP_Priority].&amp;quot; / &amp;quot;.(([$SELF:LWP_Status] ne &amp;quot;Aus&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039;)|&amp;quot;Heizung: &amp;quot;.[Heizung:opModeHeating].&amp;quot;&amp;lt;br&amp;gt;Warmwasser: &amp;quot;.[Heizung:opModeHotWater]|widget([$SELF:TimeStartHeizungWinter],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartHeizungUebergang],&amp;quot;time&amp;quot;)|[$SELF:TimeStartHeizung].widget([$SELF:TimeEndHeizung],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;Statistiken&amp;quot;|&amp;quot;Zähler&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Information&amp;quot;|&amp;quot;Wert&amp;quot;\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;EVU&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[EVU_StromZaehler:Strom_Status-02])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;LWP/KWL&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung_Zaehler])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHeating])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Warmwasser&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHotWater])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Photovoltaik&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQPool])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQTotal])\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 23:55:00 LWP_Priority frei&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-29 15:37:06 LWP_Status Aus&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 12:21:48 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 3000&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 2250&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-25 19:00:12 RunTimeMin 2400&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:55:35 RunTimePerDay 28800&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:37 TimeEnd 15:05&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 13:24:01 TimeEndHeizung 18:35&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:19 TimeStart 11:30&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 18:35:00 TimeStartHeizung 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:37:59 TimeStartHeizungUebergang 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:34:08 TimeStartHeizungWinter 02:05&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-31 12:05:34 ui_command_1 ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.54&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP&lt;br /&gt;
attr shelly01 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 412&lt;br /&gt;
attr shelly01 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung_Zaehler&amp;quot;,0));;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Wärmepumpe Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly01 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{4}(\.[0-9]{1})*$ StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{1,3}(\.[0-9]{1})*$&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter comment Version 2021.01.09 11:16&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 413&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
* [https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/ contrib/ch.eick]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39069</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39069"/>
		<updated>2024-02-08T11:25:39Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&lt;br /&gt;
[https://svn.fhem.de/fhem/trunk/fhem/contrib/ch.eick/Docker/docker-compose.yml Beispiel für eine docker-compose.yml]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ pwd&lt;br /&gt;
/home/pi/docker-compose/fhem_2022&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ cat docker-compose.yml&lt;br /&gt;
# Das Beispiel ist im contrb/ch.eick&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1_config======&lt;br /&gt;
Dieses Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehreren Wechselrichtern kann man die Module mit ihren Ausrichtungen für die Leistungsprognose alle in die erste Konfiguration legen. So ergibt sich später eine gemeinsame Prognose für die gesamte PV-Anlage. Wenn man dies auf einzelne Konfigurationsdummys aufteilt, kann man für jeden Wechselrichter eine eigene Prognose erstellen. Eine Einzel- und Gesamtprognose wäre ebenfalls denkbar. Fragen dazu bitte im Forum stellen.&lt;br /&gt;
&lt;br /&gt;
In der readingList und setList können die Namen der Ausrichtung frei gewählt werden.&lt;br /&gt;
&lt;br /&gt;
Die default Einstellungen wurden bereits über Sommer und Winter getestet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_config dummy&lt;br /&gt;
attr WR_1_config DbLogExclude .*&lt;br /&gt;
attr WR_1_config alias WR_1_config&lt;br /&gt;
attr WR_1_config comment Version 2021.04.07 12:00\&lt;br /&gt;
Passworte für die Abfrage des WR_1_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr WR_1_config event-on-change-reading .*&lt;br /&gt;
attr WR_1_config group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_config icon solar_icon&lt;br /&gt;
attr WR_1_config readingList IP-WR_1 IP-WR_1_Speicher_1 IP-WR_1_KSEM IP-FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name  module_4_name module_5_name module_1_direction module_2_direction module_3_direction module_4_direction module_5_direction module_1_count module_2_count module_3_count module_4_count module_5_count module_1_power module_2_power module_3_power module_4_power module_5_power module_1_plain module_2_plain module_3_plain module_4_plain module_5_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor forecast_factor_autocorrection Forecast_Station&lt;br /&gt;
attr WR_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_config setList IP-WR_1 IP-WR_1_Speicher_1 IP-WR_1_KSEM IP-FHEM module_1_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort module_2_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort module_3_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_4_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_5_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_1_direction module_2_direction module_3_direction module_4_direction module_5_direction module_1_count module_2_count module_3_count module_4_count module_5_count module_1_power module_2_power module_3_power module_4_power module_5_power module_1_plain module_2_plain module_3_plain module_4_plain module_5_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor forecast_factor_autocorrection Forecast_Station&lt;br /&gt;
attr WR_1_config sortby 113&lt;br /&gt;
attr WR_1_config verbose 0&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_config 2020-09-11 07:36:39 Forecast_Station P0178&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:39:26 IP-FHEM 192.168.178.xxx&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:39:44 IP-WR_1 192.168.178.yyy&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:43:27 IP-WR_1_KSEM 192.168.178.zzz&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:44:46 IP-WR_1_Speicher_1 192.168.178.xyz&lt;br /&gt;
setstate WR_1_config 2020-09-22 10:03:21 forecast_cloudk 45&lt;br /&gt;
setstate WR_1_config 2020-09-22 10:12:17 forecast_cloudk_base 0&lt;br /&gt;
setstate WR_1_config 2020-12-07 15:49:18 forecast_factor 1&lt;br /&gt;
setstate WR_1_config 2021-03-31 11:45:19 forecast_factor_autocorrection 0&lt;br /&gt;
setstate WR_1_config 2020-09-02 18:40:29 forecast_raink 20&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:52:40 forecast_raink_base 0&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:46:57 forecast_tempk 39&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:50:06 forecast_tempk_base 25&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:31:19 module_1_count 20&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:27:38 module_1_direction -90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:33:27 module_1_name WR_1_Ost&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:29:42 module_1_plain 40&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:31:09 module_1_power 310&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:10 module_2_count 16&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:13 module_2_direction 90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:33:45 module_2_name WR_1_West&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:34:14 module_2_plain 40&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:23:00 module_2_power 310&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:40 module_3_count 13&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:26 module_3_direction 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:34:09 module_3_name WR_2_Sued&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:35:08 module_3_plain 40&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:55 module_3_power 340&lt;br /&gt;
setstate WR_1_config 2021-03-29 12:20:49 module_4_count 11&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:37 module_4_direction 90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:34:27 module_4_name WR_2_West&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:34:14 module_4_plain 40&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:23:00 module_4_power 340&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:41:15 module_5_count 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:53:22 module_5_direction 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:43:38 module_5_name frei&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:50:46 module_5_plain 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:50:39 module_5_power 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1 ModbusAttr 71 60 &amp;lt;IP-Adresse&amp;gt;:1502 TCP&lt;br /&gt;
attr WR_1 DbLogExclude .*&lt;br /&gt;
attr WR_1 DbLogInclude Act_state_of_charge,Actual_Battery_charge_-minus_or_discharge_-plus_P,Actual_Battery_charge_usable_P,Battery_Total.*,Battery_charge.*,Battery_gross.*,Battery_temperature,Battery_MaxChargePowerLimitAbs,Battery_.*SOC,P_DC1,P_DC2,Total_.*,Solar_Calculation,Solar_Calculation_fc0_4h,Solar_Calculation_fc0_day,Solar_Calculation_fc0_rest,Solar_Correction.*,Solar_Cloud,Solar_East_Covered,Solar_Rain,Solar_SolarRadiation,Solar_Temp,Solar_WR_.*,Solar_middayhigh.*,SW_.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_1 alias WR_1&lt;br /&gt;
attr WR_1 alignTime 00:00&lt;br /&gt;
attr WR_1 comment Version 2022.12.30 10:00\&lt;br /&gt;
Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr WR_1 dev-h-combine 8&lt;br /&gt;
attr WR_1 dev-h-defFormat %.2f&lt;br /&gt;
attr WR_1 dev-h-defLen 2&lt;br /&gt;
attr WR_1 dev-h-defPoll 1&lt;br /&gt;
attr WR_1 dev-h-defRevRegs 1&lt;br /&gt;
attr WR_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr WR_1 dev-type-STR-format %s&lt;br /&gt;
attr WR_1 dev-type-STR-len 8&lt;br /&gt;
attr WR_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr WR_1 dev-type-STR-unpack a*&lt;br /&gt;
attr WR_1 disable 0&lt;br /&gt;
attr WR_1 event-on-change-reading Act_state_of_charge,Actual_Battery_charge_-minus_or_discharge_-plus_I,Actual_Battery_charge_-minus_or_discharge_-plus_P,Actual_Battery_charge_usable_P,Battery_Total.*,Battery_charge.*,Battery_gross.*,Battery_temperature,Battery_MaxChargePowerLimitAbs,Battery_.*SOC,Home_own_consumption.*,P_DC1,P_DC2,Solar_.*,Total_.*,SW_.*,.*_yield,Inverter_state.*,Inverter_Generation_P_Actual.*,Solar_Calculation_fc.*_day&lt;br /&gt;
attr WR_1 event-on-update-reading P_limit_from_EVU.*&lt;br /&gt;
attr WR_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1 icon sani_solar&lt;br /&gt;
attr WR_1 obj-h100-reading Total_DC_P&lt;br /&gt;
attr WR_1 obj-h1024-len 1&lt;br /&gt;
attr WR_1 obj-h1024-reading Battery_Charge_AC_P_Setpoint&lt;br /&gt;
attr WR_1 obj-h1024-set 1&lt;br /&gt;
attr WR_1 obj-h1024-unpack n&lt;br /&gt;
attr WR_1 obj-h1025-len 1&lt;br /&gt;
attr WR_1 obj-h1025-reading Battery_P_ScaleFactor&lt;br /&gt;
attr WR_1 obj-h1025-unpack n&lt;br /&gt;
attr WR_1 obj-h1026-reading Battery_Charge_AC_P_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1026-set 1&lt;br /&gt;
attr WR_1 obj-h1028-reading Battery_Charge_DC_I_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1028-set 1&lt;br /&gt;
attr WR_1 obj-h1030-reading Battery_Charge_AC_P_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1030-set 1&lt;br /&gt;
attr WR_1 obj-h1032-reading Battery_Charge_DC_I_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1032-set 1&lt;br /&gt;
attr WR_1 obj-h1034-reading Battery_Charge_DC_P_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1034-set 1&lt;br /&gt;
attr WR_1 obj-h1036-reading Battery_Charge_DC_P_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1036-set 1&lt;br /&gt;
attr WR_1 obj-h1038-reading Battery_MaxChargePowerLimitAbs&lt;br /&gt;
attr WR_1 obj-h1038-set 1&lt;br /&gt;
attr WR_1 obj-h104-format %s&lt;br /&gt;
attr WR_1 obj-h104-map 0:Normal,8:Ruhe1,16:Ruhe2,32:Ausgleichsladung,64:Tiefentladeschutz,256:externe Batteriesteuerung&lt;br /&gt;
attr WR_1 obj-h104-reading State_of_EM&lt;br /&gt;
attr WR_1 obj-h104-revRegs 0&lt;br /&gt;
attr WR_1 obj-h104-unpack N&lt;br /&gt;
attr WR_1 obj-h1040-reading Battery_MaxDischargePowerLimitAbs&lt;br /&gt;
attr WR_1 obj-h1040-set 1&lt;br /&gt;
attr WR_1 obj-h1042-reading Battery_MinSOC&lt;br /&gt;
attr WR_1 obj-h1042-set 1&lt;br /&gt;
attr WR_1 obj-h1044-reading Battery_MaxSOC&lt;br /&gt;
attr WR_1 obj-h1044-set 1&lt;br /&gt;
attr WR_1 obj-h1046-reading Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
attr WR_1 obj-h1048-reading Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
attr WR_1 obj-h1050-reading Battery_Total_AC_ChargeEnergy_ACsideToBattery&lt;br /&gt;
attr WR_1 obj-h1052-reading Battery_Total_AC_DischargeEnergy_BatteryToGrid&lt;br /&gt;
attr WR_1 obj-h1054-reading Battery_Total_AC_ChargeEnergy_gridToBattery&lt;br /&gt;
attr WR_1 obj-h1056-reading Total_DC_PV_Energy_sumOfAllPVInputs&lt;br /&gt;
attr WR_1 obj-h1058-reading Total_DC_Energy_From_PV1&lt;br /&gt;
attr WR_1 obj-h106-reading Home_own_consumption_from_Battery&lt;br /&gt;
attr WR_1 obj-h1060-reading Total_DC_Energy_From_PV2&lt;br /&gt;
attr WR_1 obj-h1062-reading Total_DC_Energy_From_PV3&lt;br /&gt;
attr WR_1 obj-h1064-reading Total_AC_Energy_ACsideToGrid&lt;br /&gt;
attr WR_1 obj-h1066-reading Total_DC_P_sumOfAllPVInputs&lt;br /&gt;
attr WR_1 obj-h1068-reading Battery_work_capacity&lt;br /&gt;
attr WR_1 obj-h1070-reading Battery_serial_number&lt;br /&gt;
attr WR_1 obj-h1072-reading Battery_Reserved_1072&lt;br /&gt;
attr WR_1 obj-h1074-reading Battery_Reserved_1074&lt;br /&gt;
attr WR_1 obj-h1076-reading Battery_Maximum_ChargePLimit_read-outFromBattery&lt;br /&gt;
attr WR_1 obj-h1078-reading Battery_Maximum_DischargePLimit_read-outFromBattery&lt;br /&gt;
attr WR_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr WR_1 obj-h1080-reading Battery_management_mode&lt;br /&gt;
attr WR_1 obj-h1080-set 1&lt;br /&gt;
attr WR_1 obj-h1081-reading Battery_Reserved_1081&lt;br /&gt;
attr WR_1 obj-h1082-reading Installed_sensor_type&lt;br /&gt;
attr WR_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr WR_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr WR_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr WR_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr WR_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr WR_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr WR_1 obj-h122-reading P_limit_from_EVU&lt;br /&gt;
attr WR_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr WR_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr WR_1 obj-h14-type STR&lt;br /&gt;
attr WR_1 obj-h144-reading Worktime&lt;br /&gt;
attr WR_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr WR_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr WR_1 obj-h154-reading I_L1&lt;br /&gt;
attr WR_1 obj-h156-reading Active_P_L1&lt;br /&gt;
attr WR_1 obj-h158-reading U_L1&lt;br /&gt;
attr WR_1 obj-h160-reading I_L2&lt;br /&gt;
attr WR_1 obj-h162-reading Active_P_L2&lt;br /&gt;
attr WR_1 obj-h164-reading U_L2&lt;br /&gt;
attr WR_1 obj-h166-reading I_L3&lt;br /&gt;
attr WR_1 obj-h168-reading Active_P_L3&lt;br /&gt;
attr WR_1 obj-h170-reading U_L3&lt;br /&gt;
attr WR_1 obj-h172-reading Total_AC_Active_P&lt;br /&gt;
attr WR_1 obj-h174-reading Total_AC_Reactive_P&lt;br /&gt;
attr WR_1 obj-h178-reading Total_AC_Apparent_P&lt;br /&gt;
attr WR_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr WR_1 obj-h194-format %.0f&lt;br /&gt;
attr WR_1 obj-h194-reading Number_of_Battery_cycles&lt;br /&gt;
attr WR_1 obj-h200-reading Actual_Battery_charge_-minus_or_discharge_-plus_I&lt;br /&gt;
attr WR_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr WR_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr WR_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr WR_1 obj-h212-reading Battery_state&lt;br /&gt;
attr WR_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr WR_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr WR_1 obj-h218-reading Cos_phi_EM&lt;br /&gt;
attr WR_1 obj-h220-reading Frequency_EM&lt;br /&gt;
attr WR_1 obj-h222-reading I_L1_EM&lt;br /&gt;
attr WR_1 obj-h224-reading Active_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h226-reading Reactive_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h228-reading Apparent_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h230-reading U_L1_EM&lt;br /&gt;
attr WR_1 obj-h232-reading I_L2_EM&lt;br /&gt;
attr WR_1 obj-h234-reading Active_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h236-reading Reactive_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h238-reading Apparent_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h240-reading U_L2_EM&lt;br /&gt;
attr WR_1 obj-h242-reading I_L3_EM&lt;br /&gt;
attr WR_1 obj-h244-reading Active_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h246-reading Reactive_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h248-reading Apparent_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h250-reading U_L3_EM&lt;br /&gt;
attr WR_1 obj-h252-reading Total_Active_P_EM&lt;br /&gt;
attr WR_1 obj-h254-reading Total_Reactive_P_EM&lt;br /&gt;
attr WR_1 obj-h256-reading Total_Apparent_P_EM&lt;br /&gt;
attr WR_1 obj-h258-reading I_DC1&lt;br /&gt;
attr WR_1 obj-h260-reading P_DC1&lt;br /&gt;
attr WR_1 obj-h266-reading U_DC1&lt;br /&gt;
attr WR_1 obj-h268-reading I_DC2&lt;br /&gt;
attr WR_1 obj-h270-reading P_DC2&lt;br /&gt;
attr WR_1 obj-h276-reading U_DC2&lt;br /&gt;
attr WR_1 obj-h278-reading I_DC3&lt;br /&gt;
attr WR_1 obj-h280-reading P_DC3&lt;br /&gt;
attr WR_1 obj-h286-reading U_DC3&lt;br /&gt;
attr WR_1 obj-h320-reading Total_yield&lt;br /&gt;
attr WR_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr WR_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr WR_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr WR_1 obj-h38-reading Software-Version_Maincontroller_MC&lt;br /&gt;
attr WR_1 obj-h38-type STR&lt;br /&gt;
attr WR_1 obj-h384-len 16&lt;br /&gt;
attr WR_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr WR_1 obj-h384-type STR&lt;br /&gt;
attr WR_1 obj-h4-format %.0f&lt;br /&gt;
attr WR_1 obj-h4-len 1&lt;br /&gt;
attr WR_1 obj-h4-reading MODBUS_Unit-ID&lt;br /&gt;
attr WR_1 obj-h4-revRegs 1&lt;br /&gt;
attr WR_1 obj-h4-unpack N&lt;br /&gt;
attr WR_1 obj-h420-reading IP-address&lt;br /&gt;
attr WR_1 obj-h420-type STR&lt;br /&gt;
attr WR_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr WR_1 obj-h428-type STR&lt;br /&gt;
attr WR_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr WR_1 obj-h436-type STR&lt;br /&gt;
attr WR_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr WR_1 obj-h446-type STR&lt;br /&gt;
attr WR_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr WR_1 obj-h454-type STR&lt;br /&gt;
attr WR_1 obj-h46-reading Software-Version_IO-Controller_IOC&lt;br /&gt;
attr WR_1 obj-h46-type STR&lt;br /&gt;
attr WR_1 obj-h5-format %.0f&lt;br /&gt;
attr WR_1 obj-h5-len 1&lt;br /&gt;
attr WR_1 obj-h5-reading MODBUS_Byte_Order_Note&lt;br /&gt;
attr WR_1 obj-h5-revRegs 1&lt;br /&gt;
attr WR_1 obj-h5-unpack N&lt;br /&gt;
attr WR_1 obj-h512-format %s&lt;br /&gt;
attr WR_1 obj-h512-reading Battery_gross_capacity&lt;br /&gt;
attr WR_1 obj-h512-unpack N&lt;br /&gt;
attr WR_1 obj-h514-len 1&lt;br /&gt;
attr WR_1 obj-h514-reading Battery_Actual_SOC&lt;br /&gt;
attr WR_1 obj-h514-unpack n&lt;br /&gt;
attr WR_1 obj-h515-format %s&lt;br /&gt;
attr WR_1 obj-h515-reading Battery_Maincontroller_MC&lt;br /&gt;
attr WR_1 obj-h515-unpack N&lt;br /&gt;
attr WR_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr WR_1 obj-h517-type STR&lt;br /&gt;
attr WR_1 obj-h525-format %s&lt;br /&gt;
attr WR_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr WR_1 obj-h525-unpack N&lt;br /&gt;
attr WR_1 obj-h527-format %s&lt;br /&gt;
attr WR_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr WR_1 obj-h527-unpack N&lt;br /&gt;
attr WR_1 obj-h529-len 4&lt;br /&gt;
attr WR_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr WR_1 obj-h529-unpack N&lt;br /&gt;
attr WR_1 obj-h531-format %.0f&lt;br /&gt;
attr WR_1 obj-h531-reading Inverter_Max_P&lt;br /&gt;
attr WR_1 obj-h531-unpack N&lt;br /&gt;
attr WR_1 obj-h56-format %.0f&lt;br /&gt;
attr WR_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr WR_1 obj-h56-unpack N&lt;br /&gt;
attr WR_1 obj-h575-reading Inverter_Generation_P_Actual&lt;br /&gt;
attr WR_1 obj-h575-unpack N&lt;br /&gt;
attr WR_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr WR_1 obj-h577-unpack N&lt;br /&gt;
attr WR_1 obj-h578-reading Total_energy&lt;br /&gt;
attr WR_1 obj-h582-reading Actual_Battery_charge-discharge_P&lt;br /&gt;
attr WR_1 obj-h586-format %s&lt;br /&gt;
attr WR_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr WR_1 obj-h586-unpack N&lt;br /&gt;
attr WR_1 obj-h6-reading Inverter_Article_number&lt;br /&gt;
attr WR_1 obj-h6-type STR&lt;br /&gt;
attr WR_1 obj-h768-len 32&lt;br /&gt;
attr WR_1 obj-h768-reading Productname&lt;br /&gt;
attr WR_1 obj-h768-type STR&lt;br /&gt;
attr WR_1 obj-h800-len 32&lt;br /&gt;
attr WR_1 obj-h800-reading Power_class&lt;br /&gt;
attr WR_1 obj-h800-type STR&lt;br /&gt;
attr WR_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1 sortby 111&lt;br /&gt;
attr WR_1 stateFormat {\&lt;br /&gt;
 my $DUMMY  = &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $Power          = ReadingsVal($name,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_P&amp;quot;,0);;\&lt;br /&gt;
 my $StatusSpeicher = ($Power &amp;lt; -10) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot; : ($Power &amp;gt; 15)?  &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot;  : &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Standby&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
    $StatusSpeicher = $StatusSpeicher.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;State_of_EM&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
    $Power          = $Power.&amp;quot; W&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
 my $Battery_temperature                  = sprintf(&amp;quot;%.1f °C&amp;quot;,ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0));;\&lt;br /&gt;
    $Battery_temperature                  = ((ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;DigitalOutputs_ConfigurationFlags&amp;quot;,0) == 9) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Lüfter An &amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;quot; : &amp;quot;&amp;lt;br&amp;gt;&amp;quot;).$Battery_temperature;;\&lt;br /&gt;
\&lt;br /&gt;
 my $Actual_Battery_charge_usable_P       = sprintf(&amp;quot;%d Wh&amp;quot;,ReadingsVal($name,&amp;quot;Actual_Battery_charge_usable_P&amp;quot;,0));;\&lt;br /&gt;
								         \&lt;br /&gt;
 my $Act_state_of_charge                  = sprintf(&amp;quot;%d %%&amp;quot;,ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
 my $SW_Total_DC_P_sumOfAllPVInputs       = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
 my $SW_Total_PV_P_reserve                = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Total_PV_P_reserve&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
\&lt;br /&gt;
 my $SW_Home_own_consumption_from_PV      = sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0));;\&lt;br /&gt;
    $SW_Home_own_consumption_from_PV = ($SW_Home_own_consumption_from_PV &amp;gt;= 0) ? $SW_Home_own_consumption_from_PV.&amp;quot; W&amp;quot; : &amp;quot;0 W&amp;quot;;;\&lt;br /&gt;
 my $SW_Home_own_consumption_from_Battery = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0));;\&lt;br /&gt;
 my $SW_Home_own_consumption_from_grid    = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0));;\&lt;br /&gt;
 my $SW_Home_own_consumption              = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
 my $Total_Active_P_EM  = sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;Total_Active_P_EM&amp;quot;,0));;\&lt;br /&gt;
 my $StatusNetz         = ($Total_Active_P_EM &amp;lt; -10) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Einspeisen&amp;lt;/span&amp;gt;&amp;quot; : ($Total_Active_P_EM &amp;gt; 15)?  &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Netzbezug&amp;lt;/span&amp;gt;&amp;quot;  : &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Standby&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
    $Total_Active_P_EM  = $Total_Active_P_EM.&amp;quot; W&amp;quot;;;\&lt;br /&gt;
	 \&lt;br /&gt;
 my $SW_Yield_Daily   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Daily&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Monthly = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Monthly&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Yearly  = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Yearly&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Total   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Total&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
\&lt;br /&gt;
 my $Solar_Calculation_fc0_4h   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_4h&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $Solar_Calculation_fc0_day  = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_day&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $Solar_Calculation_fc0_rest = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_rest&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Wechselrichter / KSEM&amp;lt;dd&amp;gt;Max DC / PV Reserve / Netz Leistung&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Total_DC_P_sumOfAllPVInputs.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Total_PV_P_reserve.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$StatusNetz.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Total_Active_P_EM.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Leistung&amp;lt;dd&amp;gt;von PV / von Batterie / vom Netz / ins Haus&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_PV.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_Battery.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_grid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Ertrag&amp;lt;dd&amp;gt;Tag / Monat / Jahr / Total&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Daily.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Monthly.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Yearly.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Total.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Prognose&amp;lt;dd&amp;gt;Tag / 4 Stunden / Resttag&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_day.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_4h.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_rest.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Speicher&amp;lt;dd&amp;gt;Temperatur / nutzbare Ladung / Status / Leistung / akt. SOC&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Battery_temperature.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Actual_Battery_charge_usable_P.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$StatusSpeicher.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Power.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$Act_state_of_charge.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1 userReadings Total_PV_P_reserve:Total_DC_P.* {my $reserve = ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0);;;; ($reserve lt 0)? 0 : round($reserve,0)  },\&lt;br /&gt;
\&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_P:[Battery_voltage|Actual_Battery_charge_-minus_or_discharge_-plus_I].* {round((ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_I&amp;quot;,0)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_P_Max:[Total_DC_P_sumOfAllPVInputs|Actual_Battery_charge_-minus_or_discharge_-plus_P].* { my $Bat_P = ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_P&amp;quot;,0);;;; ($Bat_P gt 0)? round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0) + $Bat_P,0) : round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_Battery_charge_usable_P:[Act_state_of_charge|Battery_MinSOC].* {my $x = (ReadingsVal($NAME,&amp;quot;Battery_work_capacity&amp;quot;,0)*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,0)-ReadingsVal($NAME,&amp;quot;Battery_MinSOC&amp;quot;,0))/100);;;; ($x lt 0)? 0 : round($x,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Inverter_Generation_P_Actual:Inverter_Generation_P_Actual.* {round(ReadingsVal($NAME,&amp;quot;Inverter_Generation_P_Actual&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Inverter_Generation_P_Actual&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption:[Total_Active_P_EM:|Total_AC_Active_P:].* {round(ReadingsVal($NAME,&amp;quot;Total_Active_P_EM&amp;quot;,0)+ReadingsVal($NAME,&amp;quot;Total_AC_Active_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Active_P&amp;quot;,0),0)},\&lt;br /&gt;
SW_Total_AC_Active_P:Total_AC_Active_P:.*  {round(ReadingsVal($NAME,&amp;quot;Total_AC_Active_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Active_P&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P:Total_DC_P:.* {round(ReadingsVal($NAME,&amp;quot;Total_DC_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_P&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P_sumOfAllPVInputs:Total_DC_P_sumOfAllPVInputs.* {round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_PV_P_reserve:SW_Total_DC_P_sumOfAllPVInputs.* {my $reserve = ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0) * 0.90 - ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0);;;; ($reserve lt 0)? 0 : round($reserve,0)  },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P_Max:SW_Total_DC_P_sumOfAllPVInputs.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_I&amp;quot;,0)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,0));;;; ($Bat_out gt 0)? round(ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0) + $Bat_out,0) : round(ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Yield_Daily:Daily_yield.* { round(ReadingsVal($NAME,&amp;quot;Daily_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Daily_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Monthly:Monthly_yield.* { round(ReadingsVal($NAME,&amp;quot;Monthly_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Monthly_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Yearly:Yearly_yield.* { round(ReadingsVal($NAME,&amp;quot;Yearly_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Yearly_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Total:Total_yield.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_yield&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption_from_PV:[Total_Active_P_EM|SW_Home_own_consumption:|Home_own_consumption_from_grid|Home_own_consumption_from_Battery].* { (ReadingsVal($NAME,&amp;quot;Total_Active_P_EM&amp;quot;,0) ge 0) ? ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0) :  ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0);;;; },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption_from_Battery:[SW_Home_own_consumption_from_PV|Home_own_consumption_from_Battery].* { ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0) },\&lt;br /&gt;
SW_Home_own_consumption_from_grid:[SW_Home_own_consumption_from_PV|Home_own_consumption_from_grid].* { ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0) },\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Battery_Total_AC_ChargeEnergy_ACsideToBattery:Battery_Total_AC_ChargeEnergy_ACsideToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_ChargeEnergy_ACsideToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_AC_ChargeEnergy_gridToBattery:Battery_Total_AC_ChargeEnergy_gridToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_ChargeEnergy_gridToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_AC_DischargeEnergy_BatteryToGrid:Battery_Total_AC_DischargeEnergy_BatteryToGrid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_DischargeEnergy_BatteryToGrid&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_DC_ChargeEnergy_DCsideToBattery:Battery_Total_DC_ChargeEnergy_DCsideToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_DC_ChargeEnergy_DCsideToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_DC_DischargeEnergy_DCsideFromBattery:Battery_Total_DC_DischargeEnergy_DCsideFromBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_AC_Energy_ACsideToGrid:Total_AC_Energy_ACsideToGrid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_AC_Energy_ACsideToGrid&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Energy_ACsideToGrid&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_Energy_From_PV1:Total_DC_Energy_From_PV1.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV1&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV2:Total_DC_Energy_From_PV2.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV2&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV3:Total_DC_Energy_From_PV3.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV3&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV4:Total_DC_Energy_From_PV1.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV1&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV5:Total_DC_Energy_From_PV2.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV2&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV6:Total_DC_Energy_From_PV3.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV3&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_PV_Energy_sumOfAllPVInputs:Total_DC_PV_Energy_sumOfAllPVInputs.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_PV_Energy_sumOfAllPVInputs&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_PV_Energy_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_Battery:Total_home_consumption_Battery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_Battery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_Grid:Total_home_consumption_Grid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_Grid&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_PV:Total_home_consumption_PV.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_PV&amp;quot;,0),0) }&lt;br /&gt;
attr WR_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2 ModbusAttr 71 60 &amp;lt;Ip-Adresse&amp;gt;:1502 TCP&lt;br /&gt;
attr WR_2 DbLogExclude .*&lt;br /&gt;
attr WR_2 DbLogInclude P_DC1,P_DC2,P_DC3,Total_DC_P.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_2 alias WR_2&lt;br /&gt;
attr WR_2 alignTime 00:00&lt;br /&gt;
attr WR_2 comment Version 2021.06.02 14:00\&lt;br /&gt;
Kostal Plenticore Plus 7&lt;br /&gt;
attr WR_2 dev-h-combine 8&lt;br /&gt;
attr WR_2 dev-h-defFormat %.2f&lt;br /&gt;
attr WR_2 dev-h-defLen 2&lt;br /&gt;
attr WR_2 dev-h-defPoll 1&lt;br /&gt;
attr WR_2 dev-h-defRevRegs 1&lt;br /&gt;
attr WR_2 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr WR_2 dev-type-STR-format %s&lt;br /&gt;
attr WR_2 dev-type-STR-len 8&lt;br /&gt;
attr WR_2 dev-type-STR-revRegs 0&lt;br /&gt;
attr WR_2 dev-type-STR-unpack a*&lt;br /&gt;
attr WR_2 disable 0&lt;br /&gt;
attr WR_2 event-on-change-reading P_DC1,P_DC2,P_DC3,Total_DC_P.*,Total_DC_PV_Energy.*,Total_AC_Active_P.*,Inverter_state.*,Inverter_Generation_P_Actual.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_2 group PV Eigenverbrauch&lt;br /&gt;
attr WR_2 icon sani_solar&lt;br /&gt;
attr WR_2 obj-h100-reading Total_DC_P&lt;br /&gt;
attr WR_2 obj-h1058-reading Total_DC_Energy_From_PV1&lt;br /&gt;
attr WR_2 obj-h1060-reading Total_DC_Energy_From_PV2&lt;br /&gt;
attr WR_2 obj-h1062-reading Total_DC_Energy_From_PV3&lt;br /&gt;
attr WR_2 obj-h1064-reading Total_AC_Energy_ACsideToGrid&lt;br /&gt;
attr WR_2 obj-h1066-reading Total_DC_P_sumOfAllPVInputs&lt;br /&gt;
attr WR_2 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr WR_2 obj-h122-reading P_limit_from_EVU&lt;br /&gt;
attr WR_2 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr WR_2 obj-h14-type STR&lt;br /&gt;
attr WR_2 obj-h144-reading Worktime&lt;br /&gt;
attr WR_2 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr WR_2 obj-h152-reading Grid_frequency&lt;br /&gt;
attr WR_2 obj-h154-reading I_L1&lt;br /&gt;
attr WR_2 obj-h156-reading Active_P_L1&lt;br /&gt;
attr WR_2 obj-h158-reading U_L1&lt;br /&gt;
attr WR_2 obj-h160-reading I_L2&lt;br /&gt;
attr WR_2 obj-h162-reading Active_P_L2&lt;br /&gt;
attr WR_2 obj-h164-reading U_L2&lt;br /&gt;
attr WR_2 obj-h166-reading I_L3&lt;br /&gt;
attr WR_2 obj-h168-reading Active_P_L3&lt;br /&gt;
attr WR_2 obj-h170-reading U_L3&lt;br /&gt;
attr WR_2 obj-h172-reading Total_AC_Active_P&lt;br /&gt;
attr WR_2 obj-h174-reading Total_AC_Reactive_P&lt;br /&gt;
attr WR_2 obj-h178-reading Total_AC_Apparent_P&lt;br /&gt;
attr WR_2 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr WR_2 obj-h254-reading Total_Reactive_P_EM&lt;br /&gt;
attr WR_2 obj-h258-reading I_DC1&lt;br /&gt;
attr WR_2 obj-h260-reading P_DC1&lt;br /&gt;
attr WR_2 obj-h266-reading U_DC1&lt;br /&gt;
attr WR_2 obj-h268-reading I_DC2&lt;br /&gt;
attr WR_2 obj-h270-reading P_DC2&lt;br /&gt;
attr WR_2 obj-h276-reading U_DC2&lt;br /&gt;
attr WR_2 obj-h278-reading I_DC3&lt;br /&gt;
attr WR_2 obj-h280-reading P_DC3&lt;br /&gt;
attr WR_2 obj-h286-reading U_DC3&lt;br /&gt;
attr WR_2 obj-h320-reading Total_yield&lt;br /&gt;
attr WR_2 obj-h322-reading Daily_yield&lt;br /&gt;
attr WR_2 obj-h324-reading Yearly_yield&lt;br /&gt;
attr WR_2 obj-h326-reading Monthly_yield&lt;br /&gt;
attr WR_2 obj-h38-reading Software-Version_Maincontroller_MC&lt;br /&gt;
attr WR_2 obj-h38-type STR&lt;br /&gt;
attr WR_2 obj-h384-len 16&lt;br /&gt;
attr WR_2 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr WR_2 obj-h384-type STR&lt;br /&gt;
attr WR_2 obj-h420-reading IP-address&lt;br /&gt;
attr WR_2 obj-h420-type STR&lt;br /&gt;
attr WR_2 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr WR_2 obj-h428-type STR&lt;br /&gt;
attr WR_2 obj-h436-reading IP-gateway&lt;br /&gt;
attr WR_2 obj-h436-type STR&lt;br /&gt;
attr WR_2 obj-h446-reading IP-DNS1&lt;br /&gt;
attr WR_2 obj-h446-type STR&lt;br /&gt;
attr WR_2 obj-h454-reading IP-DNS2&lt;br /&gt;
attr WR_2 obj-h454-type STR&lt;br /&gt;
attr WR_2 obj-h46-reading Software-Version_IO-Controller_IOC&lt;br /&gt;
attr WR_2 obj-h46-type STR&lt;br /&gt;
attr WR_2 obj-h529-len 4&lt;br /&gt;
attr WR_2 obj-h529-reading Work_Capacity&lt;br /&gt;
attr WR_2 obj-h529-unpack N&lt;br /&gt;
attr WR_2 obj-h531-format %.0f&lt;br /&gt;
attr WR_2 obj-h531-reading Inverter_Max_P&lt;br /&gt;
attr WR_2 obj-h531-unpack N&lt;br /&gt;
attr WR_2 obj-h535-revRegs 0&lt;br /&gt;
attr WR_2 obj-h535-unpack n&lt;br /&gt;
attr WR_2 obj-h551-revRegs 0&lt;br /&gt;
attr WR_2 obj-h559-revRegs 0&lt;br /&gt;
attr WR_2 obj-h56-format %.0f&lt;br /&gt;
attr WR_2 obj-h56-reading Inverter_state&lt;br /&gt;
attr WR_2 obj-h56-unpack N&lt;br /&gt;
attr WR_2 obj-h575-reading Inverter_Generation_P_Actual&lt;br /&gt;
attr WR_2 obj-h575-unpack N&lt;br /&gt;
attr WR_2 obj-h577-len 2&lt;br /&gt;
attr WR_2 obj-h577-reading Generation_Energy&lt;br /&gt;
attr WR_2 obj-h577-unpack N&lt;br /&gt;
attr WR_2 obj-h578-reading Total_energy&lt;br /&gt;
attr WR_2 obj-h6-reading Inverter_Article_number&lt;br /&gt;
attr WR_2 obj-h6-type STR&lt;br /&gt;
attr WR_2 obj-h768-len 32&lt;br /&gt;
attr WR_2 obj-h768-reading Productname&lt;br /&gt;
attr WR_2 obj-h768-type STR&lt;br /&gt;
attr WR_2 obj-h800-len 32&lt;br /&gt;
attr WR_2 obj-h800-reading Power_class&lt;br /&gt;
attr WR_2 obj-h800-type STR&lt;br /&gt;
attr WR_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2 sortby 211&lt;br /&gt;
attr WR_2 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub plenticore_auth {&lt;br /&gt;
   my ($step, $user, $logdevice, $randomString, $nonce, $salt, $rounds, $transactionId, $token) = @_;&lt;br /&gt;
&lt;br /&gt;
   my $verbose     = AttrVal($logdevice,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
   my $PASSWD = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_&amp;quot;.$logdevice.&amp;quot;_&amp;quot;.$user);&lt;br /&gt;
&lt;br /&gt;
   if ($verbose &amp;gt;= 3) {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====Start plenticore_auth==============================&amp;quot;;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_step         : &amp;quot;.$step;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_user         : &amp;quot;.$user;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_device       : &amp;quot;.$logdevice;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_KeyValue read: PW_&amp;quot;.$logdevice.&amp;quot;_&amp;quot;.$user;&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   if($step eq &amp;quot;start&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     my @chars = (&#039;0&#039;..&#039;9&#039;, &#039;A&#039;..&#039;Z&#039;, &#039;a&#039;..&#039;z&#039;);&lt;br /&gt;
     my $len = 12;&lt;br /&gt;
     my $string;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     while($len--){ $string .= $chars[rand @chars] };&lt;br /&gt;
     $string = encode(&amp;quot;UTF-8&amp;quot;, $string);&lt;br /&gt;
     $string = decode(&amp;quot;UTF-8&amp;quot;, $string);&lt;br /&gt;
     my $u = encode_base64($string);&lt;br /&gt;
     $u =~ s/\n$//g;&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;nonce&amp;quot;: &amp;quot;&#039;.$u.&#039;&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;&#039;.$user.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_nonce        : &amp;quot;.$u;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
     &lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; auth_randomString64 &amp;quot;.$u) ;&lt;br /&gt;
 &lt;br /&gt;
    return $message;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
   ######### This code is identical for finish and session #################&lt;br /&gt;
   my $bitSalt = decode_base64($salt);&lt;br /&gt;
   my $r = derive( &#039;SHA-256&#039;, $PASSWD, $bitSalt, $rounds );&lt;br /&gt;
   my $ck = encode(&#039;UTF-8&#039;, &amp;quot;Client Key&amp;quot;);&lt;br /&gt;
   my $s = hmac_sha256($ck, $r);&lt;br /&gt;
   my $underscore = sha256($s);&lt;br /&gt;
   my $d = &amp;quot;n=&amp;quot;.$user.&amp;quot;,r=&amp;quot;.$randomString.&amp;quot;,r=&amp;quot;.$nonce.&amp;quot;,s=&amp;quot;.$salt.&amp;quot;,i=&amp;quot;.$rounds.&amp;quot;,c=biws,r=&amp;quot;.$nonce;&lt;br /&gt;
&lt;br /&gt;
   if ($verbose &amp;gt;= 3) {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_randomString : &amp;quot;.$randomString;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_nonce        : &amp;quot;.$nonce;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_salt         : &amp;quot;.$salt;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_rounds       : &amp;quot;.$rounds;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_transactionId: &amp;quot;.$transactionId;&lt;br /&gt;
   };&lt;br /&gt;
   &lt;br /&gt;
   if($step eq &amp;quot;finish&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
     my $sk = encode(&#039;UTF-8&#039;, &amp;quot;Server Key&amp;quot;);&lt;br /&gt;
     my $c = hmac_sha256($sk, $r);&lt;br /&gt;
     my $pd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $p = hmac_sha256($pd, $c);&lt;br /&gt;
     my $gd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $g = hmac_sha256($gd, $underscore);&lt;br /&gt;
     my $f = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $g1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $s1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $f1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $j = 0;&lt;br /&gt;
     for($j=0; $j&amp;lt;length($g); $j++) {&lt;br /&gt;
        $g1 = substr($g,$j,1);&lt;br /&gt;
        $s1 = substr($s,$j,1);&lt;br /&gt;
        $f1 = $s1 ^ $g1 ;&lt;br /&gt;
        $f = $f.$f1;&lt;br /&gt;
     }&lt;br /&gt;
     my $pe = encode_base64($f);&lt;br /&gt;
     $pe =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $proof = decode(&#039;UTF-8&#039;, $pe);&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;transactionId&amp;quot;: &amp;quot;&#039;.$transactionId.&#039;&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;&#039;.$proof.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_proof        : &amp;quot;.$proof;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     return $message;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
   if($step eq &amp;quot;session&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_token        : &amp;quot;.$token;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
     my $sk = encode(&#039;UTF-8&#039;, &amp;quot;Session Key&amp;quot;);&lt;br /&gt;
     my $dd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $protocol_key = hmac_sha256($sk, $dd, $s, $underscore);&lt;br /&gt;
&lt;br /&gt;
     my $t = &amp;quot;7244ba6f73c8cdc47b232e1311451939&amp;quot;;&lt;br /&gt;
     $t =~ s/([a-fA-F0-9][a-fA-F0-9])/chr(hex($1))/eg;&lt;br /&gt;
     my $e2 = Crypt::AuthEnc::GCM-&amp;gt;new(&amp;quot;AES&amp;quot;, $protocol_key, $t);&lt;br /&gt;
     my $tt = encode(&#039;UTF-8&#039;, $token);&lt;br /&gt;
     my $e2ct = $e2-&amp;gt;encrypt_add($tt);&lt;br /&gt;
     my $authtag = $e2-&amp;gt;encrypt_done();&lt;br /&gt;
&lt;br /&gt;
     $tt = encode_base64($t);&lt;br /&gt;
     $tt =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $iv = decode(&#039;UTF-8&#039;, $tt);&lt;br /&gt;
&lt;br /&gt;
     my $aa = encode_base64($authtag);&lt;br /&gt;
     $aa =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     $authtag = decode(&#039;UTF-8&#039;, $aa);&lt;br /&gt;
&lt;br /&gt;
     my $pp = encode_base64($e2ct);&lt;br /&gt;
     $pp =~ s/\n//g;                         # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $payload = decode(&#039;UTF-8&#039;, $pp);&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;transactionId&amp;quot;: &amp;quot;&#039;.$transactionId.&#039;&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;&#039;.$iv.&#039;&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;&#039;.$authtag.&#039;&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;&#039;.$payload.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_iv           : &amp;quot;.$iv;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_authtag      : &amp;quot;.$authtag;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_payload      : &amp;quot;.$payload;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
     &lt;br /&gt;
     return $message;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master ab v1.16&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_1_API userattr get25-1Name get25JSON get25Regex&lt;br /&gt;
attr WR_1_API DbLogExclude .*&lt;br /&gt;
attr WR_1_API DbLogInclude Statistic_Autarky.*,Statistic_Energy.*,Statistic_Own.*,Statistic_Total.*,Statistic_Yield.*,SW_.*&lt;br /&gt;
attr WR_1_API authRetries 1&lt;br /&gt;
attr WR_1_API comment Version 2022.03.29 09:00\&lt;br /&gt;
Passworte für die Abfrage des WR_1_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_1_API disable 0&lt;br /&gt;
attr WR_1_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_API enableControlSet 0&lt;br /&gt;
attr WR_1_API enableCookies 1&lt;br /&gt;
attr WR_1_API event-on-change-reading Battery_.*&lt;br /&gt;
attr WR_1_API event-on-update-reading auth_.*,Statistic_Autarky.*,Statistic_EnergyFeedIn.*,Statistic_EnergyHome.*,Statistic_EnergyPv[1|2].*,Statistic_.*Consumption.*,Statistic_Energy.*_Total,Statistic_Yield.*,SW_.*&lt;br /&gt;
attr WR_1_API get01Data %START%&lt;br /&gt;
attr WR_1_API get01Name 01_auth_start&lt;br /&gt;
attr WR_1_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_1_API get02Data %FINISH%&lt;br /&gt;
attr WR_1_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_1_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_1_API get03Data %SESSION%&lt;br /&gt;
attr WR_1_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_1_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_1_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_1_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_1_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_1_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_1_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_1_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get04JSON .&lt;br /&gt;
attr WR_1_API get04Name 04_auth_me&lt;br /&gt;
attr WR_1_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_1_API get05-1Name info_api_version&lt;br /&gt;
attr WR_1_API get05-2Name info_hostname&lt;br /&gt;
attr WR_1_API get05-3Name info_name&lt;br /&gt;
attr WR_1_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_1_API get05JSON .&lt;br /&gt;
attr WR_1_API get05Name 05_info_version&lt;br /&gt;
attr WR_1_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_1_API get20-10Format %.2f&lt;br /&gt;
attr WR_1_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_1_API get20-11Format %.2f&lt;br /&gt;
attr WR_1_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_1_API get20-12Format %.2f&lt;br /&gt;
attr WR_1_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_1_API get20-13Format %.2f&lt;br /&gt;
attr WR_1_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_1_API get20-14Format %.2f&lt;br /&gt;
attr WR_1_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_1_API get20-15Format %.2f&lt;br /&gt;
attr WR_1_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_1_API get20-16Format %.2f&lt;br /&gt;
attr WR_1_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_1_API get20-17Format %.2f&lt;br /&gt;
attr WR_1_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_1_API get20-18Format %.2f&lt;br /&gt;
attr WR_1_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_1_API get20-19Format %.2f&lt;br /&gt;
attr WR_1_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_1_API get20-1Format %.2f&lt;br /&gt;
attr WR_1_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_1_API get20-20Format %.2f&lt;br /&gt;
attr WR_1_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_1_API get20-21Format %.2f&lt;br /&gt;
attr WR_1_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_1_API get20-22Format %.2f&lt;br /&gt;
attr WR_1_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_1_API get20-23Format %.2f&lt;br /&gt;
attr WR_1_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_1_API get20-24Format %.2f&lt;br /&gt;
attr WR_1_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_1_API get20-25Format %.2f&lt;br /&gt;
attr WR_1_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_1_API get20-26Format %.2f&lt;br /&gt;
attr WR_1_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_1_API get20-27Format %.2f&lt;br /&gt;
attr WR_1_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_1_API get20-28Format %.2f&lt;br /&gt;
attr WR_1_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_1_API get20-29Format %.2f&lt;br /&gt;
attr WR_1_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_1_API get20-2Format %.2f&lt;br /&gt;
attr WR_1_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_1_API get20-30Format %.2f&lt;br /&gt;
attr WR_1_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_1_API get20-31Format %.2f&lt;br /&gt;
attr WR_1_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_1_API get20-32Format %.2f&lt;br /&gt;
attr WR_1_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_1_API get20-33Format %.2f&lt;br /&gt;
attr WR_1_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_1_API get20-34Format %.2f&lt;br /&gt;
attr WR_1_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_1_API get20-35Format %.2f&lt;br /&gt;
attr WR_1_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_1_API get20-36Format %.2f&lt;br /&gt;
attr WR_1_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_1_API get20-37Format %.2f&lt;br /&gt;
attr WR_1_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_1_API get20-38Format %.2f&lt;br /&gt;
attr WR_1_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_1_API get20-39Format %.2f&lt;br /&gt;
attr WR_1_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_1_API get20-3Format %.2f&lt;br /&gt;
attr WR_1_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_1_API get20-40Format %.2f&lt;br /&gt;
attr WR_1_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_1_API get20-41Format %.2f&lt;br /&gt;
attr WR_1_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_1_API get20-42Format %.2f&lt;br /&gt;
attr WR_1_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_1_API get20-43Format %.2f&lt;br /&gt;
attr WR_1_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_1_API get20-44Format %.2f&lt;br /&gt;
attr WR_1_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_1_API get20-45Format %.2f&lt;br /&gt;
attr WR_1_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_1_API get20-46Format %.2f&lt;br /&gt;
attr WR_1_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_1_API get20-47Format %.2f&lt;br /&gt;
attr WR_1_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_1_API get20-48Format %.2f&lt;br /&gt;
attr WR_1_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_1_API get20-49Format %.2f&lt;br /&gt;
attr WR_1_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_1_API get20-4Format %.2f&lt;br /&gt;
attr WR_1_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_1_API get20-50Format %.2f&lt;br /&gt;
attr WR_1_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_1_API get20-51Format %.2f&lt;br /&gt;
attr WR_1_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_1_API get20-52Format %.2f&lt;br /&gt;
attr WR_1_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_1_API get20-53Format %.2f&lt;br /&gt;
attr WR_1_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_1_API get20-54Format %.2f&lt;br /&gt;
attr WR_1_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_1_API get20-55Format %.2f&lt;br /&gt;
attr WR_1_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_1_API get20-56Format %.2f&lt;br /&gt;
attr WR_1_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_1_API get20-57Format %.2f&lt;br /&gt;
attr WR_1_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_1_API get20-58Format %.2f&lt;br /&gt;
attr WR_1_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_1_API get20-59Format %.2f&lt;br /&gt;
attr WR_1_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_1_API get20-5Format %.2f&lt;br /&gt;
attr WR_1_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_1_API get20-60Format %.2f&lt;br /&gt;
attr WR_1_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_1_API get20-61Format %.2f&lt;br /&gt;
attr WR_1_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_1_API get20-62Format %.2f&lt;br /&gt;
attr WR_1_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_1_API get20-63Format %.2f&lt;br /&gt;
attr WR_1_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_1_API get20-64Format %.2f&lt;br /&gt;
attr WR_1_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_1_API get20-65Format %.2f&lt;br /&gt;
attr WR_1_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_1_API get20-6Format %.2f&lt;br /&gt;
attr WR_1_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_1_API get20-7Format %.2f&lt;br /&gt;
attr WR_1_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_1_API get20-8Format %.2f&lt;br /&gt;
attr WR_1_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_1_API get20-9Format %.2f&lt;br /&gt;
attr WR_1_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_1_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_1_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_1_API get21-1Name Battery_Info_Cycles&lt;br /&gt;
attr WR_1_API get21-2Name Battery_Info_FullChargeCap_E&lt;br /&gt;
attr WR_1_API get21-3Name Battery_Info_SoC&lt;br /&gt;
attr WR_1_API get21-4Format %d&lt;br /&gt;
attr WR_1_API get21-4Name Battery_Info_WorkCapacity&lt;br /&gt;
attr WR_1_API get21Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get21Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get21JSON .._processdata_.._value&lt;br /&gt;
attr WR_1_API get21Name 21_Battery_Information&lt;br /&gt;
attr WR_1_API get21URL http://%IP-WR%/api/v1/processdata/devices:local:battery/Cycles,FullChargeCap_E,SoC,WorkCapacity&lt;br /&gt;
attr WR_1_API get22-1Name Battery_InternControl_DynamicSoc_Enable&lt;br /&gt;
attr WR_1_API get22-2Name Battery_Control&lt;br /&gt;
attr WR_1_API get22-3Format %d&lt;br /&gt;
attr WR_1_API get22-3Name Battery_InternControl_MinHomeConsumption&lt;br /&gt;
attr WR_1_API get22-4Name Battery_InternControl_MinSoc&lt;br /&gt;
attr WR_1_API get22-5Name Battery_InternControl_SmartBatteryControl_Enable&lt;br /&gt;
attr WR_1_API get22-6Name Battery_InternControl_Strategy&lt;br /&gt;
attr WR_1_API get22-7Name Battery_InternControl_Type&lt;br /&gt;
attr WR_1_API get22Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get22Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get22JSON .._value&lt;br /&gt;
attr WR_1_API get22Name 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API get22URL http://%IP-WR%/api/v1/settings/devices:local/Battery:ExternControl,Battery:Type,Battery:MinHomeComsumption,Battery:Strategy,Battery:MinSoc,Battery:SmartBatteryControl:Enable,Battery:DynamicSoc:Enable,Battery:Type&lt;br /&gt;
attr WR_1_API get23-10Format %d&lt;br /&gt;
attr WR_1_API get23-10Name Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
attr WR_1_API get23-11Format %d&lt;br /&gt;
attr WR_1_API get23-11Name Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
attr WR_1_API get23-12Format %d&lt;br /&gt;
attr WR_1_API get23-12Name Battery_ExternControl_MaxSocRel&lt;br /&gt;
attr WR_1_API get23-13Format %d&lt;br /&gt;
attr WR_1_API get23-13Name Battery_ExternControl_MinSocRel&lt;br /&gt;
attr WR_1_API get23-1Name Battery_ComMonitor_Enable&lt;br /&gt;
attr WR_1_API get23-2Format %d&lt;br /&gt;
attr WR_1_API get23-2Name Battery_ComMonitor_Time&lt;br /&gt;
attr WR_1_API get23-3Name Battery_Control&lt;br /&gt;
attr WR_1_API get23-4Format %.2f&lt;br /&gt;
attr WR_1_API get23-4Name Battery_ExternControl_AcPowerAbs&lt;br /&gt;
attr WR_1_API get23-5Format %.2f&lt;br /&gt;
attr WR_1_API get23-5Name Battery_ExternControl_AcPowerRel&lt;br /&gt;
attr WR_1_API get23-6Format %.2f&lt;br /&gt;
attr WR_1_API get23-6Name Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
attr WR_1_API get23-7Format %.2f&lt;br /&gt;
attr WR_1_API get23-7Name Battery_ExternControl_DcCurrentRel&lt;br /&gt;
attr WR_1_API get23-8Format %.2f&lt;br /&gt;
attr WR_1_API get23-8Name Battery_ExternControl_DcPowerAbs&lt;br /&gt;
attr WR_1_API get23-9Format %.2f&lt;br /&gt;
attr WR_1_API get23-9Name Battery_ExternControl_DcPowerRel&lt;br /&gt;
attr WR_1_API get23Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get23Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get23JSON .._value&lt;br /&gt;
attr WR_1_API get23Name 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API get23URL http://%IP-WR%/api/v1/settings/devices:local/Battery:ComMonitor:Enable,Battery:ComMonitor:Time,Battery:ExternControl,Battery:ExternControl:AcPowerAbs,Battery:ExternControl:AcPowerRel,Battery:ExternControl:DcCurrentAbs,Battery:ExternControl:DcCurrentRel,Battery:ExternControl:DcPowerAbs,Battery:ExternControl:DcPowerRel,Battery:ExternControl:MaxChargePowerAbs,Battery:ExternControl:MaxDischargePowerAbs,Battery:ExternControl:MaxSocRel,Battery:ExternControl:MinSocRel&lt;br /&gt;
attr WR_1_API get24-1Name Battery_TimeControl_1&lt;br /&gt;
attr WR_1_API get24-2Name Battery_TimeControl_2&lt;br /&gt;
attr WR_1_API get24-3Name Battery_TimeControl_3&lt;br /&gt;
attr WR_1_API get24-4Name Battery_TimeControl_4&lt;br /&gt;
attr WR_1_API get24-5Name Battery_TimeControl_5&lt;br /&gt;
attr WR_1_API get24-6Name Battery_TimeControl_6&lt;br /&gt;
attr WR_1_API get24-7Name Battery_TimeControl_7&lt;br /&gt;
attr WR_1_API get24-8Name Battery_TimeControl&lt;br /&gt;
attr WR_1_API get24Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get24Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get24JSON .._value&lt;br /&gt;
attr WR_1_API get24Name 24_Battery_TimeControl&lt;br /&gt;
attr WR_1_API get24URL http://%IP-WR%/api/v1/settings/devices:local/Battery:TimeControl:Enable,Battery:TimeControl:ConfMon,Battery:TimeControl:ConfTue,Battery:TimeControl:ConfWed,Battery:TimeControl:ConfThu,Battery:TimeControl:ConfFri,Battery:TimeControl:ConfSat,Battery:TimeControl:ConfSun&lt;br /&gt;
attr WR_1_API get25Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get25Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get25Name 25_Battery_EM_State&lt;br /&gt;
attr WR_1_API get25URL http://%IP-WR%/api/v1/processdata/devices:local/EM_State&lt;br /&gt;
attr WR_1_API get40-1Name EnergyMgmt_AcStorage&lt;br /&gt;
attr WR_1_API get40-2Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get40JSON .._value&lt;br /&gt;
attr WR_1_API get40Name 40_Generator_und_EnergieMgmt&lt;br /&gt;
attr WR_1_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable,EnergyMgmt:AcStorage&lt;br /&gt;
attr WR_1_API get41-1Name DigitalOutputs_ConfigurationFlags&lt;br /&gt;
attr WR_1_API get41-2Name DigitalOutputs_DelayTime&lt;br /&gt;
attr WR_1_API get41-3Name DigitalOutputs_PowerMode_OffPowerThreshold&lt;br /&gt;
attr WR_1_API get41-4Name DigitalOutputs_PowerMode_OnPowerThreshold&lt;br /&gt;
attr WR_1_API get41-5Name DigitalOutputs_SwitchOffDuration&lt;br /&gt;
attr WR_1_API get41-6Name DigitalOutputs_TimeMode_MaxNoOfSwitchingCyclesPerDay&lt;br /&gt;
attr WR_1_API get41-7Name DigitalOutputs_TimeMode_PowerThreshold&lt;br /&gt;
attr WR_1_API get41-8Name DigitalOutputs_TimeMode_RunTime&lt;br /&gt;
attr WR_1_API get41-9Name DigitalOutputs_TimeMode_StableTime&lt;br /&gt;
attr WR_1_API get41Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get41Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get41JSON .._value&lt;br /&gt;
attr WR_1_API get41Name 41_DigitalOutputs&lt;br /&gt;
attr WR_1_API get41URL http://%IP-WR%/api/v1/settings/devices:local/DigitalOutputs:Customer:ConfigurationFlags,DigitalOutputs:Customer:DelayTime,DigitalOutputs:Customer:PowerMode:OffPowerThreshold,DigitalOutputs:Customer:PowerMode:OnPowerThreshold,DigitalOutputs:Customer:SwitchOffDuration,DigitalOutputs:Customer:TimeMode:MaxNoOfSwitchingCyclesPerDay,DigitalOutputs:Customer:TimeMode:PowerThreshold,DigitalOutputs:Customer:TimeMode:RunTime,DigitalOutputs:Customer:TimeMode:StableTime&lt;br /&gt;
attr WR_1_API get51Name 51_modules_list&lt;br /&gt;
attr WR_1_API get51URL http://%IP-WR%/api/v1/modules&lt;br /&gt;
attr WR_1_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_1_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_1_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_1_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get60Name 60_update_status&lt;br /&gt;
attr WR_1_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_API icon sani_solar&lt;br /&gt;
attr WR_1_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_1_API reading0101JSON nonce&lt;br /&gt;
attr WR_1_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_1_API reading0102JSON rounds&lt;br /&gt;
attr WR_1_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_1_API reading0103JSON salt&lt;br /&gt;
attr WR_1_API reading0103Name auth_salt&lt;br /&gt;
attr WR_1_API reading0104JSON transactionId&lt;br /&gt;
attr WR_1_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_1_API reading0201JSON signature&lt;br /&gt;
attr WR_1_API reading0201Name auth_signature&lt;br /&gt;
attr WR_1_API reading0202JSON token&lt;br /&gt;
attr WR_1_API reading0202Name auth_token&lt;br /&gt;
attr WR_1_API reading0301JSON message&lt;br /&gt;
attr WR_1_API reading0301Name info_message&lt;br /&gt;
attr WR_1_API reading0302JSON error&lt;br /&gt;
attr WR_1_API reading0302Name info_error&lt;br /&gt;
attr WR_1_API reading03JSON sessionId&lt;br /&gt;
attr WR_1_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_1_API reading25Name Battery_EM_State&lt;br /&gt;
attr WR_1_API reading25OMap 0:Normal,8:Ruhe1,16:Ruhe2,32:Ausgleichsladung,64:Tiefentladeschutz&lt;br /&gt;
attr WR_1_API reading25Regex EM_State.*value&amp;quot;:(\d+)&lt;br /&gt;
attr WR_1_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_1_API replacement01Mode expression&lt;br /&gt;
attr WR_1_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_1_API replacement01Value {ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_1_API replacement02Mode expression&lt;br /&gt;
attr WR_1_API replacement02Regex %START%&lt;br /&gt;
attr WR_1_API replacement02Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_1_API replacement04Mode expression&lt;br /&gt;
attr WR_1_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_1_API replacement04Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_1_API replacement05Mode expression&lt;br /&gt;
attr WR_1_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_1_API replacement05Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_1_API replacement06Mode reading&lt;br /&gt;
attr WR_1_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_1_API replacement06Value auth_signature&lt;br /&gt;
attr WR_1_API replacement07Mode reading&lt;br /&gt;
attr WR_1_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_1_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_1_API replacement08Mode expression&lt;br /&gt;
attr WR_1_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_1_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_1_API replacement09Mode expression&lt;br /&gt;
attr WR_1_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_1_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_1_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set06Method POST&lt;br /&gt;
attr WR_1_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_1_API set06NoArg 1&lt;br /&gt;
attr WR_1_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_1_API set2201Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:DynamicSoc:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2201FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2201Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2201Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2201Hint 0,1&lt;br /&gt;
attr WR_1_API set2201Method PUT&lt;br /&gt;
attr WR_1_API set2201Name 22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
attr WR_1_API set2201URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2203Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinHomeComsumption&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2203FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2203Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2203Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2203Hint slider,50,50,8000&lt;br /&gt;
attr WR_1_API set2203Method PUT&lt;br /&gt;
attr WR_1_API set2203Name 22_03_Battery_MinHomeConsumption&lt;br /&gt;
attr WR_1_API set2203URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2204Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinSoc&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2204FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2204Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2204Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2204Hint slider,5,5,100&lt;br /&gt;
attr WR_1_API set2204Method PUT&lt;br /&gt;
attr WR_1_API set2204Name 22_04_Battery_MinSoc&lt;br /&gt;
attr WR_1_API set2204URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2205Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:SmartBatteryControl:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2205FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2205Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2205Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2205Hint 0,1&lt;br /&gt;
attr WR_1_API set2205Method PUT&lt;br /&gt;
attr WR_1_API set2205Name 22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr WR_1_API set2205URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2206Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Strategy&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2206FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2206Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2206Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2206Hint 1,2&lt;br /&gt;
attr WR_1_API set2206Method PUT&lt;br /&gt;
attr WR_1_API set2206Name 22_06_Battery_Strategy&lt;br /&gt;
attr WR_1_API set2206URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2207Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Type&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2207FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2207Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2207Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2207Hint 0,4&lt;br /&gt;
attr WR_1_API set2207Method PUT&lt;br /&gt;
attr WR_1_API set2207Name 22_07_Battery_Type&lt;br /&gt;
attr WR_1_API set2207URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2300Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2300FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2300Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2300Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2300Hint 0,1,2&lt;br /&gt;
attr WR_1_API set2300Method PUT&lt;br /&gt;
attr WR_1_API set2300Name 23_00_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2300URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2301Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:AcPowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2301FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2301Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2301Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2301Method PUT&lt;br /&gt;
attr WR_1_API set2301Name 23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
attr WR_1_API set2301URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2302Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:AcPowerRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2302FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2302Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2302Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2302Method PUT&lt;br /&gt;
attr WR_1_API set2302Name 23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
attr WR_1_API set2302URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2303Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcCurrentAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2303FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2303Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2303Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2303Method PUT&lt;br /&gt;
attr WR_1_API set2303Name 23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
attr WR_1_API set2303URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2304Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcCurrentRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2304FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2304Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2304Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2304Method PUT&lt;br /&gt;
attr WR_1_API set2304Name 23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
attr WR_1_API set2304URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2305Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcPowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2305FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2305Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2305Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2305Method PUT&lt;br /&gt;
attr WR_1_API set2305Name 23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
attr WR_1_API set2305URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2306Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcPowerRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2306FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2306Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2306Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2306Method PUT&lt;br /&gt;
attr WR_1_API set2306Name 23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
attr WR_1_API set2306URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2307Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxChargePowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2307FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2307Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2307Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2307Method PUT&lt;br /&gt;
attr WR_1_API set2307Name 23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
attr WR_1_API set2307URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2308Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxDischargePowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2308FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2308Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2308Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2308Method PUT&lt;br /&gt;
attr WR_1_API set2308Name 23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
attr WR_1_API set2308URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2309Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxSocRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2309FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2309Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2309Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2309Hint slider,30,5,100&lt;br /&gt;
attr WR_1_API set2309Method PUT&lt;br /&gt;
attr WR_1_API set2309Name 23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
attr WR_1_API set2309URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2310Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MinSocRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2310FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2310Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2310Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2310Hint slider,0,5,100&lt;br /&gt;
attr WR_1_API set2310Method PUT&lt;br /&gt;
attr WR_1_API set2310Name 23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
attr WR_1_API set2310URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2311Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ComMonitor:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2311FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2311Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2311Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2311Hint 0,1&lt;br /&gt;
attr WR_1_API set2311Method PUT&lt;br /&gt;
attr WR_1_API set2311Name 23_11_Battery_ComMonitor_Enable&lt;br /&gt;
attr WR_1_API set2311URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2312Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ComMonitor:Time&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2312FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2312Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2312Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2312Hint slider,0,10,600&lt;br /&gt;
attr WR_1_API set2312Method PUT&lt;br /&gt;
attr WR_1_API set2312Name 23_12_Battery_ComMonitor_Time&lt;br /&gt;
attr WR_1_API set2312URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set4002FollowGet 40_Generator_und EnergieMgmt&lt;br /&gt;
attr WR_1_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_1_API set4002Method PUT&lt;br /&gt;
attr WR_1_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set4101Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:DelayTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;5&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:PowerMode:OnPowerThreshold&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;100000&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:MaxNoOfSwitchingCyclesPerDay&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:PowerThreshold&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:RunTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;30&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:StableTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set4101FollowGet 41_DigitalOutputs&lt;br /&gt;
attr WR_1_API set4101Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set4101Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set4101Hint 0,9,13,14&lt;br /&gt;
attr WR_1_API set4101Method PUT&lt;br /&gt;
attr WR_1_API set4101Name 41_01_DigitalOutputs&lt;br /&gt;
attr WR_1_API set4101URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_1_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_1_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_1_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_1_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_1_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_1_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_1_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_1_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_1_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_1_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_1_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_1_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_1_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_1_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_1_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_1_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_1_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_1_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_1_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_1_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_1_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_1_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_1_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_1_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_1_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_1_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_1_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_1_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_1_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_1_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_1_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_1_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_1_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_1_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_1_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_1_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_1_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_1_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_1_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_1_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_1_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_1_API set50JSON .&lt;br /&gt;
attr WR_1_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_1_API set50ParseResponse 1&lt;br /&gt;
attr WR_1_API set50TextArg 1&lt;br /&gt;
attr WR_1_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_1_API set6001Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set6001Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set6001Method POST&lt;br /&gt;
attr WR_1_API set6001Name 60_01_Reset_Wechselrichter&lt;br /&gt;
attr WR_1_API set6001NoArg 1&lt;br /&gt;
attr WR_1_API set6001URL http://%IP-WR%/api/v1/system/reboot&lt;br /&gt;
attr WR_1_API showBody 1&lt;br /&gt;
attr WR_1_API showError 1&lt;br /&gt;
attr WR_1_API sid01Data %START%&lt;br /&gt;
attr WR_1_API sid01ParseResponse 1&lt;br /&gt;
attr WR_1_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_1_API sid02Data %FINISH%&lt;br /&gt;
attr WR_1_API sid02ParseResponse 1&lt;br /&gt;
attr WR_1_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_1_API sid03Data %SESSION%&lt;br /&gt;
attr WR_1_API sid03ParseResponse 1&lt;br /&gt;
attr WR_1_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_1_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_1_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API sortby 112&lt;br /&gt;
attr WR_1_API stateFormat {\&lt;br /&gt;
 my $calcVal = 0;;\&lt;br /&gt;
 my $WR      = &amp;quot;WR_1&amp;quot;;;\&lt;br /&gt;
 my $YearBefore      = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
 my $YearPrevious    = ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
   $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(time_str2num(ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $QuarterBefore   = &amp;quot;LogDBRep_Statistic_previous_Quarter&amp;quot;;;\&lt;br /&gt;
 my $QuarterPrevious = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
 foreach my $i (1,2,3,4) {if (ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,&amp;quot;Q&amp;quot;.$i,0) eq &amp;quot;previous&amp;quot;){ $QuarterPrevious = &amp;quot;Q&amp;quot;.$i }};;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvt   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Total_AC_Active_P&amp;quot;,0) );;\&lt;br /&gt;
 my $pvtd  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvtm  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvtm .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_Yield&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvty  = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvty .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv    = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0) );;\&lt;br /&gt;
 my $pvd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomePv&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvy   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $gfi   =  sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0),0)):  0) );;\&lt;br /&gt;
 my $gfid  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $gfim  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $gfim .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomeFeedInGrid&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $gfiy  = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $gfiy .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $eb    = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0),0) : 0) );;\&lt;br /&gt;
 my $ebd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $ebm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $ebm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomeGrid&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $eby   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $eby  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvb   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0));;\&lt;br /&gt;
 my $pvbd  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvbm  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvbm .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, 158+ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_Statistic_EnergyHomeBat&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvby  = sprintf(&amp;quot;%05d&amp;quot;,158+ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvby .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $et    = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0)) );;\&lt;br /&gt;
 my $etd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $etm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $etm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_TotalConsumption&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $ety   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $ety  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $valA  = ReadingsVal($WR, &amp;quot;SW_Total_AC_Active_P&amp;quot;,0)-ReadingsVal($WR, &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0);;\&lt;br /&gt;
    $calcVal = ($valA &amp;gt; 0) ? round($valA /($valA + ReadingsVal($WR, &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0;;\&lt;br /&gt;
 my $aq    = sprintf(&amp;quot;%4d %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
 \&lt;br /&gt;
 my $aqd   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Day&amp;quot;,0) );;\&lt;br /&gt;
 my $aqm   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Month&amp;quot;,0) );;\&lt;br /&gt;
 my $aqy   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0) );;\&lt;br /&gt;
    $aqy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %3d %%&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $valS  = ReadingsVal($WR,&amp;quot;SW_Total_AC_Active_P&amp;quot;,0);;\&lt;br /&gt;
    $calcVal = ($valS &amp;gt; 0) ? round((ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0) + ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)) / $valS * 100 ,0) : 0;;\&lt;br /&gt;
 my $sq    =  sprintf(&amp;quot;%4d %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
\&lt;br /&gt;
 my $sqd   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Day&amp;quot;,0) );;\&lt;br /&gt;
 my $sqm   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Month&amp;quot;,0) );;\&lt;br /&gt;
 my $sqy   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Year&amp;quot;,0) );;\&lt;br /&gt;
    $sqy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %3d %%&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $date  = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;auth_me_authenticated&amp;quot;,0))));;\&lt;br /&gt;
 my $md    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;auth_me_authenticated&amp;quot;,0))));;\&lt;br /&gt;
 my $cd    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Day&amp;quot;,0))));;\&lt;br /&gt;
 my $cm    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Month&amp;quot;,0))));;\&lt;br /&gt;
    $cm   .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.POSIX::strftime(&amp;quot;%d.%m&amp;quot;,localtime(time_str2num(ReadingsTimestamp(&amp;quot;$QuarterBefore&amp;quot;,&amp;quot;$QuarterPrevious&amp;quot;,0) ))) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $cy    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0))));;\&lt;br /&gt;
    $cy   .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.$YearPrevious : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Statistik vom $date in kWh&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;aktuell&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Monat&amp;quot;.(($QuarterPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.$QuarterPrevious : &amp;quot;&amp;quot;).&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Jahr&amp;quot;.(($YearPrevious ne &amp;quot;0&amp;quot;) ? &amp;quot; / Vorjahr&amp;quot; : &amp;quot;&amp;quot;).&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Erzeugung PV-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug von PV&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug von Batterie&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvbd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvbm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug ins Haus (Energieverbrauch)&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug vom Netz&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Einspeisung ins Netz&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnet um&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr WR_1_API timeout 7&lt;br /&gt;
attr WR_1_API userReadings Statistic_EnergyHomePvSum_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;0&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;0&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;0&amp;quot;) ),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)),0)},\&lt;br /&gt;
Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)),0)},\&lt;br /&gt;
Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyPv1_Day:Statistic_EnergyPv1_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Month:Statistic_EnergyPv1_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Total:Statistic_EnergyPv1_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Year:Statistic_EnergyPv1_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Day:Statistic_EnergyPv2_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Month:Statistic_EnergyPv2_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Total:Statistic_EnergyPv2_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Year:Statistic_EnergyPv2_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Day:Statistic_EnergyPv3_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Month:Statistic_EnergyPv3_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Total:Statistic_EnergyPv3_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Year:Statistic_EnergyPv3_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyPv4_Day:Statistic_EnergyPv1_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Month:Statistic_EnergyPv1_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Total:Statistic_EnergyPv1_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Year:Statistic_EnergyPv1_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Day:Statistic_EnergyPv2_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Month:Statistic_EnergyPv2_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Total:Statistic_EnergyPv2_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Year:Statistic_EnergyPv2_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Day:Statistic_EnergyPv3_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Month:Statistic_EnergyPv3_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Total:Statistic_EnergyPv3_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Year:Statistic_EnergyPv3_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Yield_Day:Statistic_Yield_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Total:Statistic_Yield_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Total&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)),0)},\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)),0)},\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Day:SW_Statistic_Yield_Day.* {   (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Day&amp;quot;  ,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Month:SW_Statistic_Yield_Month.* { (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Month&amp;quot;,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Year:SW_Statistic_Yield_Year.* {  (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Year&amp;quot; ,0)) * 1000 },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Day:SW_Statistic_Yield_Day.* {   (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Day&amp;quot;  ,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Month:SW_Statistic_Yield_Month.* { (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Month&amp;quot;,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Year:SW_Statistic_Yield_Year.* {  (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Year&amp;quot; ,0)) * 1000 },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;  ,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot; ,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {   round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHome_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0) },\&lt;br /&gt;
SW_Statistic_EnergyHome_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) },\&lt;br /&gt;
SW_Statistic_EnergyHome_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_TotalConsumption_Day:SW_Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Day&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;,0) ) ,0)},\&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0)},\&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Autarky_Day:SW_Statistic_EnergyHomePvSum_Day.* { my $SW_Statistic_EnergyHome_Day = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Day&amp;quot;,0) ;; ($SW_Statistic_EnergyHome_Day eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Day&amp;quot;,0) / $SW_Statistic_EnergyHome_Day *100,0) },\&lt;br /&gt;
SW_Statistic_Autarky_Month:SW_Statistic_EnergyHomePvSum_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Month&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Month&amp;quot;,0) *100,0) },\&lt;br /&gt;
SW_Statistic_Autarky_Year:SW_Statistic_EnergyHomePvSum_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Year&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Year&amp;quot;,0) *100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Day:SW_Statistic_EnergyHomePvSum_Day.* {my $SW_Statistic_Yield_Day = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Day eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Day&amp;quot;  ,0) / $SW_Statistic_Yield_Day*100,0) },\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Month:SW_Statistic_EnergyHomePvSum_Month.* {my $SW_Statistic_Yield_Month = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Month eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Month&amp;quot;  ,0) / $SW_Statistic_Yield_Month*100,0) },\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Year:SW_Statistic_EnergyHomePvSum_Year.* {my $SW_Statistic_Yield_Year = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Year eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Year&amp;quot;  ,0) / $SW_Statistic_Yield_Year*100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyChargeGrid_Total:Statistic_EnergyChargeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyChargeInvIn_Total:Statistic_EnergyChargeInvIn_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargeInvIn_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyChargePv_Total:Statistic_EnergyChargePv_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargePv_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyDischargeGrid_Total:Statistic_EnergyDischargeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyDischargeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyDischarge_Total:Statistic_EnergyDischarge_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyDischarge_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeBat_Total:Statistic_EnergyHomeBat_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Total:Statistic_EnergyHomeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeOwn_Total:Statistic_EnergyHomeOwn_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeOwn_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Total:Statistic_EnergyHomePv_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHome_Total:Statistic_EnergyHome_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHome_Total&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Autarky_Total:SW_Statistic_EnergyHomePv_Total.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Total&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Total&amp;quot;,0) *100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Total:SW_Statistic_EnergyHomePv_Total.* {my $SW_Statistic_Yield_Total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Total&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Total eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Total&amp;quot; ,0) / $SW_Statistic_Yield_Total*100,0) }&lt;br /&gt;
attr WR_1_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erweiterung im PV_Schedule, um die Zählerstände zu speichern&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 1)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_2_API DbLogExclude .*&lt;br /&gt;
attr WR_2_API DbLogInclude Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API authRetries 1&lt;br /&gt;
attr WR_2_API comment Version 2021.04.27 16:00\&lt;br /&gt;
Passworte für die Abfrage des WR_2_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_2_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_2_API disable 0&lt;br /&gt;
attr WR_2_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_2_API enableControlSet 0&lt;br /&gt;
attr WR_2_API enableCookies 1&lt;br /&gt;
attr WR_2_API event-on-update-reading auth_.*,Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API get01Data %START%&lt;br /&gt;
attr WR_2_API get01Name 01_auth_start&lt;br /&gt;
attr WR_2_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API get02Data %FINISH%&lt;br /&gt;
attr WR_2_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_2_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API get03Data %SESSION%&lt;br /&gt;
attr WR_2_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_2_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_2_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_2_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_2_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_2_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_2_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_2_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get04JSON .&lt;br /&gt;
attr WR_2_API get04Name 04_auth_me&lt;br /&gt;
attr WR_2_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_2_API get05-1Name info_api_version&lt;br /&gt;
attr WR_2_API get05-2Name info_hostname&lt;br /&gt;
attr WR_2_API get05-3Name info_name&lt;br /&gt;
attr WR_2_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_2_API get05JSON .&lt;br /&gt;
attr WR_2_API get05Name 05_info_version&lt;br /&gt;
attr WR_2_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_2_API get20-10Format %.2f&lt;br /&gt;
attr WR_2_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-11Format %.2f&lt;br /&gt;
attr WR_2_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-12Format %.2f&lt;br /&gt;
attr WR_2_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-13Format %.2f&lt;br /&gt;
attr WR_2_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_2_API get20-14Format %.2f&lt;br /&gt;
attr WR_2_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_2_API get20-15Format %.2f&lt;br /&gt;
attr WR_2_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_2_API get20-16Format %.2f&lt;br /&gt;
attr WR_2_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_2_API get20-17Format %.2f&lt;br /&gt;
attr WR_2_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_2_API get20-18Format %.2f&lt;br /&gt;
attr WR_2_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_2_API get20-19Format %.2f&lt;br /&gt;
attr WR_2_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_2_API get20-1Format %.2f&lt;br /&gt;
attr WR_2_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_2_API get20-20Format %.2f&lt;br /&gt;
attr WR_2_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_2_API get20-21Format %.2f&lt;br /&gt;
attr WR_2_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_2_API get20-22Format %.2f&lt;br /&gt;
attr WR_2_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_2_API get20-23Format %.2f&lt;br /&gt;
attr WR_2_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_2_API get20-24Format %.2f&lt;br /&gt;
attr WR_2_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_2_API get20-25Format %.2f&lt;br /&gt;
attr WR_2_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_2_API get20-26Format %.2f&lt;br /&gt;
attr WR_2_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-27Format %.2f&lt;br /&gt;
attr WR_2_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-28Format %.2f&lt;br /&gt;
attr WR_2_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-29Format %.2f&lt;br /&gt;
attr WR_2_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_2_API get20-2Format %.2f&lt;br /&gt;
attr WR_2_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_2_API get20-30Format %.2f&lt;br /&gt;
attr WR_2_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_2_API get20-31Format %.2f&lt;br /&gt;
attr WR_2_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_2_API get20-32Format %.2f&lt;br /&gt;
attr WR_2_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_2_API get20-33Format %.2f&lt;br /&gt;
attr WR_2_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_2_API get20-34Format %.2f&lt;br /&gt;
attr WR_2_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_2_API get20-35Format %.2f&lt;br /&gt;
attr WR_2_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_2_API get20-36Format %.2f&lt;br /&gt;
attr WR_2_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_2_API get20-37Format %.2f&lt;br /&gt;
attr WR_2_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_2_API get20-38Format %.2f&lt;br /&gt;
attr WR_2_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_2_API get20-39Format %.2f&lt;br /&gt;
attr WR_2_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_2_API get20-3Format %.2f&lt;br /&gt;
attr WR_2_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_2_API get20-40Format %.2f&lt;br /&gt;
attr WR_2_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_2_API get20-41Format %.2f&lt;br /&gt;
attr WR_2_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_2_API get20-42Format %.2f&lt;br /&gt;
attr WR_2_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_2_API get20-43Format %.2f&lt;br /&gt;
attr WR_2_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_2_API get20-44Format %.2f&lt;br /&gt;
attr WR_2_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_2_API get20-45Format %.2f&lt;br /&gt;
attr WR_2_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_2_API get20-46Format %.2f&lt;br /&gt;
attr WR_2_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_2_API get20-47Format %.2f&lt;br /&gt;
attr WR_2_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_2_API get20-48Format %.2f&lt;br /&gt;
attr WR_2_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_2_API get20-49Format %.2f&lt;br /&gt;
attr WR_2_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_2_API get20-4Format %.2f&lt;br /&gt;
attr WR_2_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_2_API get20-50Format %.2f&lt;br /&gt;
attr WR_2_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_2_API get20-51Format %.2f&lt;br /&gt;
attr WR_2_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_2_API get20-52Format %.2f&lt;br /&gt;
attr WR_2_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_2_API get20-53Format %.2f&lt;br /&gt;
attr WR_2_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_2_API get20-54Format %.2f&lt;br /&gt;
attr WR_2_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_2_API get20-55Format %.2f&lt;br /&gt;
attr WR_2_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_2_API get20-56Format %.2f&lt;br /&gt;
attr WR_2_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_2_API get20-57Format %.2f&lt;br /&gt;
attr WR_2_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_2_API get20-58Format %.2f&lt;br /&gt;
attr WR_2_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_2_API get20-59Format %.2f&lt;br /&gt;
attr WR_2_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_2_API get20-5Format %.2f&lt;br /&gt;
attr WR_2_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_2_API get20-60Format %.2f&lt;br /&gt;
attr WR_2_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_2_API get20-61Format %.2f&lt;br /&gt;
attr WR_2_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_2_API get20-62Format %.2f&lt;br /&gt;
attr WR_2_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_2_API get20-63Format %.2f&lt;br /&gt;
attr WR_2_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_2_API get20-64Format %.2f&lt;br /&gt;
attr WR_2_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_2_API get20-65Format %.2f&lt;br /&gt;
attr WR_2_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_2_API get20-6Format %.2f&lt;br /&gt;
attr WR_2_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_2_API get20-7Format %.2f&lt;br /&gt;
attr WR_2_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_2_API get20-8Format %.2f&lt;br /&gt;
attr WR_2_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_2_API get20-9Format %.2f&lt;br /&gt;
attr WR_2_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_2_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_2_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_2_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_2_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get40Name 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable&lt;br /&gt;
attr WR_2_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_2_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_2_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_2_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get60Name 60_update_status&lt;br /&gt;
attr WR_2_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_2_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_2_API icon sani_solar&lt;br /&gt;
attr WR_2_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_2_API reading0101JSON nonce&lt;br /&gt;
attr WR_2_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_2_API reading0102JSON rounds&lt;br /&gt;
attr WR_2_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_2_API reading0103JSON salt&lt;br /&gt;
attr WR_2_API reading0103Name auth_salt&lt;br /&gt;
attr WR_2_API reading0104JSON transactionId&lt;br /&gt;
attr WR_2_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_2_API reading0201JSON signature&lt;br /&gt;
attr WR_2_API reading0201Name auth_signature&lt;br /&gt;
attr WR_2_API reading0202JSON token&lt;br /&gt;
attr WR_2_API reading0202Name auth_token&lt;br /&gt;
attr WR_2_API reading0301JSON message&lt;br /&gt;
attr WR_2_API reading0301Name info_message&lt;br /&gt;
attr WR_2_API reading0302JSON error&lt;br /&gt;
attr WR_2_API reading0302Name info_error&lt;br /&gt;
attr WR_2_API reading03JSON sessionId&lt;br /&gt;
attr WR_2_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_2_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_2_API replacement01Mode expression&lt;br /&gt;
attr WR_2_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_2_API replacement01Value {ReadingsVal(&amp;quot;WR_2_config&amp;quot;,&amp;quot;IP-WR_2&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement02Mode expression&lt;br /&gt;
attr WR_2_API replacement02Regex %START%&lt;br /&gt;
attr WR_2_API replacement02Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement04Mode expression&lt;br /&gt;
attr WR_2_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_2_API replacement04Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement05Mode expression&lt;br /&gt;
attr WR_2_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_2_API replacement05Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement06Mode reading&lt;br /&gt;
attr WR_2_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_2_API replacement06Value auth_signature&lt;br /&gt;
attr WR_2_API replacement07Mode reading&lt;br /&gt;
attr WR_2_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_2_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_2_API replacement08Mode expression&lt;br /&gt;
attr WR_2_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_2_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API replacement09Mode expression&lt;br /&gt;
attr WR_2_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_2_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set06Method POST&lt;br /&gt;
attr WR_2_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_2_API set06NoArg 1&lt;br /&gt;
attr WR_2_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_2_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_2_API set4002FollowGet 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_2_API set4002Method PUT&lt;br /&gt;
attr WR_2_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_2_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_2_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_2_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_2_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_2_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_2_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_2_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_2_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_2_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_2_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_2_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_2_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_2_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_2_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_2_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_2_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_2_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_2_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_2_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_2_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_2_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_2_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_2_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_2_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_2_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_2_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_2_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_2_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_2_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_2_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_2_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_2_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_2_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_2_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_2_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_2_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_2_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_2_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_2_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_2_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_2_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_2_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_2_API set50JSON .&lt;br /&gt;
attr WR_2_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_2_API set50ParseResponse 1&lt;br /&gt;
attr WR_2_API set50TextArg 1&lt;br /&gt;
attr WR_2_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_2_API showBody 1&lt;br /&gt;
attr WR_2_API showError 1&lt;br /&gt;
attr WR_2_API sid01Data %START%&lt;br /&gt;
attr WR_2_API sid01ParseResponse 1&lt;br /&gt;
attr WR_2_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API sid02Data %FINISH%&lt;br /&gt;
attr WR_2_API sid02ParseResponse 1&lt;br /&gt;
attr WR_2_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API sid03Data %SESSION%&lt;br /&gt;
attr WR_2_API sid03ParseResponse 1&lt;br /&gt;
attr WR_2_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API sortby 212&lt;br /&gt;
attr WR_2_API timeout 7&lt;br /&gt;
attr WR_2_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion Solar_forecast() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive        An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning       Aus = momentan keine Steuerung&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0          0 = Es gibt kein Mittags Hoch. Wird aus Solar_forecast() gesetzt &lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der PV_1:Solar_middayhigh_fc0_start wird dann unlimitiert bis zur PV_1:Solar_middayhigh_fc0_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_ExternControl DOIF ################################################################################################################\&lt;br /&gt;
## 1 Speicher Status vom WR_1_Speicher_1 aktualisieren.\&lt;br /&gt;
##   Dies geschieht über das WR_1_API Device, da der Speicher direkt am Wechselrichter angeschlossen ist.\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_WR_1_Speicher_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [:52]                                                           ## jede Stunde\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 21_Battery_Information&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 22_Battery_InternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 23_Battery_ExternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_1  : Speicher Status abfrage&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Wenn die Ladung im Herbst/Winter unter MinSoc geht allen PV Überschuss in die Batterie laden\&lt;br /&gt;
##\&lt;br /&gt;
## Im Winter kann der MinSoc, durch den WR Eigenverbrauch, unterschritten werden, deshalb wird vorher auf\&lt;br /&gt;
## smarte_laden umgeschaltet, bis die Batterie wieder einen hohen Soc erreicht hat. Siehe cmd_3 laden_beendet\&lt;br /&gt;
##\&lt;br /&gt;
2_smart_Laden_start_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [WR_ctl:Yield_fc0_day] &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit]     ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
       and [WR_1:Act_state_of_charge] &amp;lt;= [WR_1_API:Battery_InternControl_MinSoc]  ## Achtung der Speicherstand wird zu niedrig\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100             ## Der Speicher steht auf Entladen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.1: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.1: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_smart_Laden_start_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [WB_1:lp_1_ChargeStat]      eq &amp;quot;loading&amp;quot;                        ## Ein Fahrzeug wird gerade geladen\&lt;br /&gt;
     and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;Aus&amp;quot;                            ## Der Speicher darf nicht zum Laden verwendet werden\&lt;br /&gt;
     or\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot;                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot; ) {\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before aktiv&amp;quot;);;                ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before inaktiv&amp;quot;);;              ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
    } else {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_2.2: WallBox es wird gerade geladen&amp;quot;};;       ## Der vorherige Zustand war schon bekannt\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.2: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.2: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Beim erreichen von 90% Soc die Entladung wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:SpeicherEntladung] eq &amp;quot;Automatik&amp;quot;                            ## Nur für den Automatik Modus\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100         ## Das Speicher Entladen ist geperrt\&lt;br /&gt;
       and\&lt;br /&gt;
       [WR_1:Act_state_of_charge] &amp;gt;= 80                                  ## Der Speicher ist bereits 80% voll\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell aktiviert\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.1: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.1: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_smart_Laden_beenden_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;inaktiv&amp;quot;                      ## Vorher war es nicht aktiv\&lt;br /&gt;
      )\&lt;br /&gt;
     or  [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;                             ## Der Speicher darf zum Laden verwendet werden\&lt;br /&gt;
     or  [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                       ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.2: Batterie wird mit &amp;quot;.[?$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.2: Batterie auf &amp;quot;.[?WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (    [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;\&lt;br /&gt;
        and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;) {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF cmd_3.2: MaxSOC Limitierung wegen Wallboxnutzung abgeschaltet&amp;quot;;;}\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Wenn vor dem WB_1 laden das smart_Laden aktiv gewesen ist geht es zurück in den Zustand\&lt;br /&gt;
## \&lt;br /&gt;
3_smart_Laden_umschalten_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;aktiv&amp;quot;                        ## Vorher war es nicht aktiv\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_umschalten_WB_1&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                        ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: WB_1 laden beendet, reaktivieren des smart_Laden&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.3: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.3: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Bei Zeitsteuerung und guter Prognose bei 40% wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Zeit\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [$SELF:SpeicherEntladung]  eq &amp;quot;Zeit&amp;quot;                            ## Nur für den Zeit Modus\&lt;br /&gt;
     and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]            ## Zeitfenster aktiv ist\&lt;br /&gt;
     and [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                        ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (\&lt;br /&gt;
            [WR_1:Act_state_of_charge] &amp;gt;= 40                             ## und einem Stand von Soc 40%\&lt;br /&gt;
        and\&lt;br /&gt;
            ([WR_ctl:Yield_fc0_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit]   ## wenn es heute oder \&lt;br /&gt;
          or [WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit])  ## morgen viel Leistung gibt\&lt;br /&gt;
       )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_zeit&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, SpeicherExternTrigger, freigegeben&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Die Leistungsprognose von &amp;quot;.[$SELF:SpeicherMinSOC_fc1_Limit].&amp;quot; wird überschritten&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;frei&amp;quot;);;                         ## Trigger freigeben\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                           ## Signalisiere entladen im stateFormat\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);; ## Speicher für Entladung freigeben\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Freigabe der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. ([07:00-16:00]\&lt;br /&gt;
4_Trigger\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]       ## Zeitfenster aktiv ist\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot;                               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot; ) {                             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;  ## Speicher für Entladung freigeben\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                            ## Signalisiere entladen im stateFormat\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_4  : SpeicherExternTrigger, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Sperren der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. [16:00-07:00]\&lt;br /&gt;
5_Trigger_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitEnde]-[$SELF:SpeicherZeitStart]]       ## Zeitfenster verlassen wurde\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger_sperren&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;## Speicher für Entladung sperren\&lt;br /&gt;
  set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                             ## Signalisiere gesperrt im stateFormat\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
    {Log 3, &amp;quot;$SELF cmd_5  : SpeicherExternTrigger, Entlademodus gesperrt (Tarif oder Trigger)&amp;quot;};;\&lt;br /&gt;
 }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
6_Kommando_Wiederholung\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [WR_1_API:Battery_Control] &amp;gt; 0 and                                ## Wenn die ExternControl am WR konfiguriert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatActive]  eq &amp;quot;An&amp;quot; and                      ## Wenn die ExternControl Aktiviert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatRunning] eq &amp;quot;An&amp;quot; and                      ## Wenn es  ExternControl Kommandos zum Senden gibt\&lt;br /&gt;
       [  {sunrise_abs(&amp;quot;HORIZON=+5.0&amp;quot;,0,&amp;quot;6:00&amp;quot;,&amp;quot;08:35&amp;quot;)}                 ## Innerhalb der Photovoltaik Zeit\&lt;br /&gt;
        - {sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)} ] and\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot; ) {              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   my $MaxChargePowerTime = 0;;\&lt;br /&gt;
   my $MaxChargePowerAbs_midday = 0;;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {                              ## Hier können noch Testmeldungen hin\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : SpeicherMiddayControlRunning &amp;quot;.[$SELF:SpeicherMiddayControlRunning];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_start   &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_stop    &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop];;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlRunning] eq &amp;quot;An&amp;quot; ) {                  ## Wurde ein Mittagshoch ermittelt und aktiviert?\&lt;br /&gt;
\&lt;br /&gt;
     if ( [WR_1:Act_state_of_charge] &amp;gt;= [WR_1_API:Battery_InternControl_MinSoc] *3 ) {\&lt;br /&gt;
       if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs 0&amp;quot;);;     ## nicht vor z.B. 09:00 Uhr starten. Ladung auf 0 Watt setzen\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                                              ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot; Uhr noch nicht laden&amp;quot;;;\&lt;br /&gt;
         }\&lt;br /&gt;
       } else {                                                          ## Ist noch Vormittag?\&lt;br /&gt;
         if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
           ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning]);;\&lt;br /&gt;
           set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMidday_MaxSOC].&#039;)&#039;);;\&lt;br /&gt;
           if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                       ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; limitieren&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning].&amp;quot; limitiert&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSOC auf &amp;quot;.[$SELF:SpeicherMidday_MaxSOC].&amp;quot; % limitiert&amp;quot;;;\&lt;br /&gt;
           }\&lt;br /&gt;
         }\&lt;br /&gt;
       }\&lt;br /&gt;
     } else {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_6  : Battery_InternControl_MinSoc auf &amp;quot;.([WR_1_API:Battery_InternControl_MinSoc] *3).&amp;quot; % laden&amp;quot;;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
     if (::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) &amp;lt;= time and  ## Es ist Mittag\&lt;br /&gt;
         time &amp;lt;= ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
\&lt;br /&gt;
       my $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;)+3600 ));;\&lt;br /&gt;
          $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ));;\&lt;br /&gt;
\&lt;br /&gt;
       if ([$SELF:SpeicherMaxSOCControlRunning] eq &amp;quot;An&amp;quot; and                     ## Somit bleibt weniger Platz im Speicher und es ist\&lt;br /&gt;
           time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.$wait.&amp;quot;:00&amp;quot;) ) {  ## besser nicht zu früh beginnen.\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden wegen MaxSoc von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; auf &amp;quot;.$wait.&amp;quot; Uhr verschoben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
       } else {                                                                 ## auch jetzt nicht mit voller Leistung laden\&lt;br /&gt;
\&lt;br /&gt;
         if ([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0) {            ## dynamische Leistungsermittlung oder vorgewählter Wert\&lt;br /&gt;
           $MaxChargePowerTime       = ::round((::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) - time) / 3600 , 2);;  ## Mittags Ladezeit bestimmen\&lt;br /&gt;
\&lt;br /&gt;
           my $MaxChargePowerLimit   = (1 - ::round($MaxChargePowerTime,2) * [$SELF:SpeicherMidday_MaxChargePowerSteigung]);;  ## Zu Beginn etwas langsamer anfangen, empirisch ermittelt\&lt;br /&gt;
\&lt;br /&gt;
           $MaxChargePowerAbs_midday = ::round( [WR_1:Battery_work_capacity] * ([$SELF:SpeicherMaxSOC_Actual] - [WR_1:Act_state_of_charge]) / 100 * $MaxChargePowerLimit, 0);;\&lt;br /&gt;
\&lt;br /&gt;
           if ($MaxChargePowerAbs_midday &amp;lt; 500) { $MaxChargePowerAbs_midday = 500 };;## Nicht unter 1000\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Mittags $MaxChargePowerTime h mit $MaxChargePowerAbs_midday W laden&amp;quot;;;\&lt;br /&gt;
         } else {\&lt;br /&gt;
           $MaxChargePowerAbs_midday = [$SELF:SpeicherMidday_MaxChargePowerAbs_midday];; ## Nimm den vorgewählten Wert\&lt;br /&gt;
         };;\&lt;br /&gt;
\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs $MaxChargePowerAbs_midday&amp;quot;);;\&lt;br /&gt;
         set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMaxSOC_Actual].&#039;)&#039;);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; bis &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; freigegeben&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf $MaxChargePowerAbs_midday limitiert&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;\&lt;br /&gt;
         };;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
\&lt;br /&gt;
     if (time &amp;gt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {    ## Es ist Nachmittag und die\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                                         ## Mittagssteuerung wird abgeschaltet\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl nach &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; beendet&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;An&amp;quot; and ## Nur MaxSOC soll begrenzt werden\&lt;br /&gt;
       [$SELF:SpeicherMaxSOC_Actual] &amp;lt;= 100                        and                                          \&lt;br /&gt;
       ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;Aus&amp;quot;) { ##  sobald die Mittagssteuerung fertig ist\&lt;br /&gt;
     if ([WR_1:SW_Home_own_consumption_from_Battery] &amp;gt; 500) {             ## Sollte der Speicher bereits jetzt verwendet werden ist es besser\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                 ## die MaxSOC Begrenzung zu stoppen\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMaxSOCControl wegen Speicher Nutzung am Nachmittag beendet&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_6  : ExternControl Kommando Wiederholung erledigt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Bestimmung eines möglichen SOC für den nächsten Morgen und\&lt;br /&gt;
##   Vorbereitung für ein Leistungshoch am Mittag\&lt;br /&gt;
##\&lt;br /&gt;
7_SOC_Calculation\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       ([WR_1_API:Battery_Control] &amp;gt; 0 and                               ## Ist die ExternControl am WR aktiviert\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot;   or                ## Ist MaxSOC Limit konfiguriert\&lt;br /&gt;
         [$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; ) and               ## Ist Midday Kontrolle konfiguriert\&lt;br /&gt;
        [$SELF:SpeicherMaxSOC_MinSOC_Time]  eq &amp;quot;NULL&amp;quot; and                ## Wurde ein minimum SOC bereits ermittelt\&lt;br /&gt;
        [{sunrise_abs(&amp;quot;HORIZON=+4.0&amp;quot;,0,&amp;quot;5:50&amp;quot;,&amp;quot;08:35&amp;quot;)} - 10:00 ] and\&lt;br /&gt;
        [WR_1:SW_Home_own_consumption_from_PV] == [WR_1:SW_Home_own_consumption] ## Die PV Leistung reicht für&#039;s Haus\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot; ) {                     ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   my $MinSOC_Time   = &amp;quot;gefunden&amp;quot;;;                                       ## Nur einmal am Tag bearbeiten\&lt;br /&gt;
   my $MinSOC_MinSOC = ::round([WR_1:Act_state_of_charge],0);;            ## Festgestellter MinSOC am Morgen          Magic ???\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,$MinSOC_Time);;\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,$MinSOC_MinSOC);;\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                               ## merken und melden\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_MinSOC_Time &amp;quot;.$MinSOC_Time.&amp;quot; &amp;quot;.$MinSOC_MinSOC.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot; and\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt; 100 and     ## Der Speicher darf nicht im smart_laden sein\&lt;br /&gt;
       [Pool_Counter:countsPerDay] == 0 and                              ## Achtung der Pool und auch die LWP\&lt;br /&gt;
       [LWP_Counter:countsPerDay]  == 0 ) {                              ##    sollten nicht mehr früh morgens laufen\&lt;br /&gt;
\&lt;br /&gt;
     my $SpeicherSOCMinimum = [WR_1_API:Battery_InternControl_MinSoc]*3;; ## 3x MinSOC als reserve vorsehen\&lt;br /&gt;
     my $SpeicherSOCDayBefore = ::round(ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;, 100),0);; ## wie voll war er gestern noch?\&lt;br /&gt;
     my $SpeicherSOCNew       = 0;;\&lt;br /&gt;
     my $SpeicherSOCDelta     = 0;;\&lt;br /&gt;
\&lt;br /&gt;
     if ([WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMaxSOC_fc1_Limit] and\&lt;br /&gt;
         $MinSOC_MinSOC                   &amp;gt; $SpeicherSOCMinimum ) {      ## Ist der Speicher voller als er müsste?\&lt;br /&gt;
\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Leistung Prognose &amp;quot;.[WR_ctl:Yield_fc1_day].&amp;quot; wh &amp;gt; Schwellwert &amp;quot;.[$SELF:SpeicherMaxSOC_fc1_Limit].&amp;quot; wh&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Speicherladung aktuell $MinSOC_MinSOC % &amp;gt; Minimum $SpeicherSOCMinimum %&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
       $SpeicherSOCDelta = $MinSOC_MinSOC - $SpeicherSOCMinimum;;         ## Was wäre noch übrig?\&lt;br /&gt;
       if ($SpeicherSOCDelta &amp;lt;= 10) {                                    ## Das lohnt sich nicht\&lt;br /&gt;
         $SpeicherSOCNew = $SpeicherSOCDayBefore;;                        ## den Wert von gestern einfach beibehalten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCDayBefore);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; % gesichert&amp;quot;};;\&lt;br /&gt;
       } else {\&lt;br /&gt;
         $SpeicherSOCNew = ::round(($SpeicherSOCDayBefore+$SpeicherSOCDayBefore-$SpeicherSOCDelta)/2 ,0);;  ## um den Durchschnitt verringern\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCNew);;           ## Das soll heute in den Speicher\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCNew.&amp;quot; % neu berechnet und gesichert&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
       if ($SpeicherSOCNew &amp;gt; 0) {                                        ## Es gibt einen neuen MaxSoc\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;               ## Senden starten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Wiederholung starten\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual &amp;quot;.$SpeicherSOCNew.&amp;quot; % geplant&amp;quot;};;\&lt;br /&gt;
       } else {                                                          ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
     } else {                                                            ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
       if ($MinSOC_MinSOC  &amp;lt; $SpeicherSOCMinimum ) {                     ## MaxSoc leicht erhöhen, da er etwas zu niedrig war\&lt;br /&gt;
         $SpeicherSOCNew   = ::round($SpeicherSOCDayBefore+$SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         $SpeicherSOCDelta = ::round($SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,$SpeicherSOCNew);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore wurde um &amp;quot;.$SpeicherSOCDelta.&amp;quot; erhöht&amp;quot;};;\&lt;br /&gt;
       }\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt, da die Prognose für morgen zu schlecht ist&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; and                   ## Soll für mittags noch Platz gehalten werden?\&lt;br /&gt;
       [WR_ctl:Yield_fc0_middayhigh] == 1 ) {                                                    \&lt;br /&gt;
																	                           \&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Die Mittagskontrolle aktivieren\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){                              ## (die Uhrzeiten wurden bereits durch Solar_forecast() im WR_1 Device eingetragen)\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie SpeicherMiddayControlRunning vorbereitet&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_start &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_start&amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_stop  &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_stop &amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {                                                              ## Kein Mittagshoch\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMiddayControl es wird kein Middayhigh geben&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Reset der ExternControl Kommandos\&lt;br /&gt;
##\&lt;br /&gt;
8_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;16:00&amp;quot;,&amp;quot;21:00&amp;quot;)}]                ## hier sollte das Ende der PV-Zeit sein\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot;                                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot; ) {                               ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
																			                   \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Max SOC Steuerung zurücksetzen\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                           ## SpeicherMaxSOC_Actual auf Default\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,[WR_1:Act_state_of_charge]);;   ## Den vor Tages Wert merken\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,&amp;quot;NULL&amp;quot;);;                     ## Die MinSOC Time löschen\&lt;br /&gt;
																						       \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Midday Steuerung zurücksetzen\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_8  : ExternControl zurückgesetzt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird, das ist dann im Herbst/Winter\&lt;br /&gt;
##\&lt;br /&gt;
9_MinSOC_Winter\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit] and        ## Wenn morgen das Minimum an Leistung nicht erreicht wird\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;lt; [$SELF:SpeicherMinSOC_Winter]    and        ## und der MinSoc unter der Winter Wert eingestellt ist\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot; or\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;NULL&amp;quot; and [10:01])\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Winter]);;        ## Den MinSOC anheben, um eine eventuelle\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : Batterie MinSoc auf Winterbetrieb&amp;quot;};;        ## Notladung zu verhindern\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Im Winter Betrieb keine MaxSOC Begrenzung\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## und keine Midday Steuerung\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : MaxSOC Begrenzung und Midday Steuerung im Winterbetrieb deaktiviert&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Umschaltung des MinSoc wenn viel Leistung erwartet wir, das wäre dann Frühling/Sommer\&lt;br /&gt;
##\&lt;br /&gt;
10_MinSOC_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit] and         ## sobald viel Ladung erwartet wird und der MinSoc noch\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;gt; [$SELF:SpeicherMinSOC_Sommer]    and         ## noch im Winter Modus ist\&lt;br /&gt;
        [10:09] \&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
                                                                                           \&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Sommer]);;        ## den MinSOC auf Sommerbetrieb herabsetzen, es kann\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_10 : Batterie MinSoc auf Sommerbetrieb&amp;quot;};;                              ## wieder mehr Leistung genutzt werden\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Der Speicher ist voll geladen. Hier wird das ständige nachladen auf 100 % vermieden.\&lt;br /&gt;
##\&lt;br /&gt;
11_Speicher_voll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ( [WR_ctl:Yield_fc0_day]        &amp;gt;  [$SELF:SpeicherMaxSOC_fc1_Limit] and    ## 1) sobald viel Leistung erwartet wird und der Speicher voll ist\&lt;br /&gt;
         [WR_1:Act_state_of_charge]    == 100                              and    ##    den MaxSOC wieder reduzieren, damit nicht immer nachgeladen wird\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_Actual] ne 95                                      ##   \&lt;br /&gt;
        or\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_Actual] == 95 and                                  ## 2) oder das Nachladen gestoppt wurde\&lt;br /&gt;
         [WR_1:Act_state_of_charge] &amp;lt;=  98  and                                   ##    und der SOC unte 98 % gefallen ist\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,-7200,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)}])                    ##    zwei Stunden vor Sonnenuntergang eventuell wieder nachladen\&lt;br /&gt;
       ) and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot; ) {                       ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([WR_1:Act_state_of_charge] &amp;lt;= 98) {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                         ## Eventuell noch mal nachladen\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 100 % nachladen&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;95&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                       ## Start regelmäßiges senden der Kommandos\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## MaxSOC Begrenzung weil Speicher bereits 100 % hat\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 95 % reduziert&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 WR_1_Speicher_1 DC_Power_Abs setzen z.B. zur Zwangsentladung\&lt;br /&gt;
##     dies muss manuell wiederholt werden. Danach hängt es vom WR ab, wie er die Speichersteuerung fortsetzt.\&lt;br /&gt;
12_DC_Power_Abs \&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot;                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot; ) {                        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs &amp;quot;.[$SELF:SpeicherDcPowerAbs]);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_12 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 13 WR_1_Speicher_1 Status aktualisieren.\&lt;br /&gt;
##   Dies ist momentan nur für den BYD HV Speicher, da der BYD HVS eine direkte Abfrage nicht unterstützt.\&lt;br /&gt;
##   Wer keinen BYD HV Speicher hat kann das löschen\&lt;br /&gt;
13_Status_WR_1_Speicher_1_BYD\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
      or\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot; ) {          ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 BatteryInformation&amp;quot;);;\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 StatisticInformation&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_13 : Speicher Status abfrage, BYD HV direkt&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 14_Lüfter_ein\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 15_Lüfter_aus\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 17 Wiederhole alle 180s das Kommando für die DcPowerAbs Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
17_Kommando_Wiederholung_DcPowerAbs\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [$SELF:SpeicherTriggerLaden] eq &amp;quot;An&amp;quot;  and                         ## Ist der Trigger für das Zwangsladen aktiv?\&lt;br /&gt;
       [$SELF:SpeicherDcPowerAbs]   ne 0     and                         ## Wurde eine Lade/Entlade Leistung eingestellt?\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot; ) {   ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs [$SELF:SpeicherDcPowerAbs]&amp;quot;);;\&lt;br /&gt;
   set_Exec(&amp;quot;17_Battery_EM_State&amp;quot;,30,&#039;::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;)&#039;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_17 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl alias WR_1_Speicher_1_ExternControl&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl comment Version 2023.06.21 14:00\&lt;br /&gt;
\&lt;br /&gt;
Hier können externe Trigger für die Ladung und Entladung Der Batterie gesetzt werden.\&lt;br /&gt;
Die Zeiten können z.B. durch den WeekDayTimer entsprechend an einen Stromtarif angepasst werden.\&lt;br /&gt;
Das reading SpeicherEntladung Automatik/Zeit/SpeicherTrigger ermöglicht es die Zeitsteuerung zu überschreiben.\&lt;br /&gt;
\&lt;br /&gt;
ExternTrigger\&lt;br /&gt;
Das reading dient dem Freigeben und Sperren der externen Trigger, z.B. um im Herbst/Winter das smart_laden zu steuern.\&lt;br /&gt;
Es verriegelt somit die Zeitsteuerung oder den SpeicherTrigger.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger \&lt;br /&gt;
Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API\&lt;br /&gt;
Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst\&lt;br /&gt;
SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung\&lt;br /&gt;
\&lt;br /&gt;
SpeicherTrigger:entladen,gesperrt\&lt;br /&gt;
Dieser Trigger kann durch ander Logik gesetzt werden.\&lt;br /&gt;
Auch hier wäre eine Zeitsteuerung denkbar, die entladen/gesperrt entsprechend umschaltet.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherZeitStart/SpeicherZeitEnde\&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.\&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.\&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.\&lt;br /&gt;
\&lt;br /&gt;
Speicher*ControlActive\&lt;br /&gt;
Das jeweilige reading aktiviert diese Teilkomponente für die Steuerung.\&lt;br /&gt;
Ein jeweiliges Speicher*ControlRunning signalisiert, ob gerade die Bedingungen erfüllt sind.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherCmdRepeatActive\&lt;br /&gt;
Es muss im WR die externe Speicher Steuerung aktiviert sein.\&lt;br /&gt;
Möchte man trotzdem die Sendung der ExternControl Kommandos stoppen, obwohl die Bedingungen erfüllt sind,\&lt;br /&gt;
kann man dieses reading zum Deaktivieren auf 0 setzen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMiddayControl\&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMaxSOCControl\&lt;br /&gt;
Es wird versucht den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMinSOC\&lt;br /&gt;
Dies gehört zur Basis Steuerung und schaltet den MinSOC von Sommer auf Winter Betrieb,\&lt;br /&gt;
um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl disable 0&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl readingList SpeicherExternTrigger SpeicherCmdRepeatActive SpeicherZeitStart SpeicherZeitEnde SpeicherEntladung SpeicherTrigger SpeicherMiddayControlActive SpeicherMidday_Inverter_Max_Power SpeicherMidday_MaxChargePowerAbs_morning SpeicherMidday_MaxChargePowerAbs_midday SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC SpeicherMidday_NotBefore SpeicherMinSOC_Sommer SpeicherMinSOC_Winter SpeicherMinSOC_fc1_Limit SpeicherMaxSOCControlActive SpeicherMaxSOC_Actual SpeicherMaxSOC_DayBefore SpeicherMaxSOC_fc1_Limit&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl setList SpeicherExternTrigger:frei,gesperrt SpeicherCmdRepeatActive:0,1 SpeicherZeitStart:time SpeicherZeitEnde:time SpeicherEntladung:Automatik,Zeit,Trigger SpeicherTrigger:entladen,gesperrt,none SpeicherMiddayControlActive:0,1 SpeicherMidday_Inverter_Max_Power:slider,3000,500,20000 SpeicherMidday_MaxChargePowerAbs_morning:slider,0,50,1000 SpeicherMidday_MaxChargePowerAbs_midday:slider,0,100,4700 SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC:slider,20,5,50 SpeicherMidday_NotBefore:time SpeicherMinSOC_Sommer:slider,5,1,20 SpeicherMinSOC_Winter:slider,5,1,20 SpeicherMinSOC_fc1_Limit:slider,7000,500,17000 SpeicherMaxSOCControlActive:0,1 SpeicherMaxSOC_Actual:slider,60,5,100 SpeicherMaxSOC_DayBefore:slider,15,5,100 SpeicherMaxSOC_fc1_Limit:slider,10000,2000,50000&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl sortby 122&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
#########################################################\&lt;br /&gt;
## &amp;quot;Spalte 0&amp;quot;|&amp;quot;Spalte 1&amp;quot;|&amp;quot;Spalte 2&amp;quot;|&amp;quot;Spalte 3&amp;quot;|&amp;quot;Spalte 4&amp;quot;|&amp;quot;Spalte 5&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / DcPowerAbs / Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_Speicher,smart_Laden_start,smart_Laden_beenden,smart_Laden_starten_WB_1,smart_Laden_beenden_WB_1,Kommando_Wiederholung,SOC_Calculation,Reset,DC_Power_Abs,Sommer,Winter,Speicher_voll,14_Luefter_ein,15_Luefter_aus,Status_WR_1_Speicher_1_BYD&amp;quot;) | widget([$SELF:SpeicherDcPowerAbs],&amp;quot;selectnumbers,-4500,250,4500,0,lin&amp;quot;).&amp;quot;W&amp;quot;.widget([$SELF:SpeicherTriggerLaden],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |[WR_1_API:Battery_EM_State]|([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and [WR_1_API:Battery_InternControl_MinHomeConsumption] == 30000)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;smart_Laden aktiv&amp;lt;/span&amp;gt;&#039;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Speicher&amp;lt;dd&amp;gt;Steuerung&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherEntladung],&amp;quot;uzsuDropDown,Automatik,Trigger,Zeit&amp;quot;) |&amp;quot;WB_1 Laden &amp;quot;.widget([$SELF:SpeicherWB_1_buffer],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|\&lt;br /&gt;
FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,&amp;quot;Laden&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Standby&amp;quot;,15,&amp;quot;red&amp;quot;,&amp;quot;Entladen&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_Status([WR_1:Act_state_of_charge],15,&amp;quot;red&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,49,&amp;quot;green&amp;quot;,&amp;quot;Speicher SOC&amp;quot;)|\&lt;br /&gt;
\&lt;br /&gt;
 FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],&amp;quot;orange&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],15,&amp;quot;red&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P]).&amp;quot; W&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([WR_1:Act_state_of_charge])).STY(::round([WR_1:Act_state_of_charge],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Trigger&amp;lt;dd&amp;gt;Status / ExternTrigger / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherTrigger],&amp;quot;uzsuDropDown,entladen,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherExternTrigger],&amp;quot;uzsuDropDown,frei,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherZeitStart],&amp;quot;time&amp;quot;) | widget([$SELF:SpeicherZeitEnde],&amp;quot;time&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Kommando Wiederholung&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherCmdRepeatActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherCmdRepeatRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMaxSOCControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMaxSOCControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Limit&amp;lt;dd&amp;gt;fc1_Limit / Minimum SOC Zeit / gestern / geplant&amp;lt;/dd&amp;gt;&amp;quot; |\&lt;br /&gt;
FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMaxSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;). widget([$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;) | ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot;)?(POSIX::strftime(&amp;quot;%H:%M&amp;quot;,::localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,&amp;quot;&amp;quot;)))).&amp;quot; &amp;quot;.[$SELF:SpeicherMaxSOC_MinSOC_MinSOC].&amp;quot; %&amp;quot;):&amp;quot;wartet&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_DayBefore])).STY(&amp;quot;gestern&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_DayBefore],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_Actual])).STY(&amp;quot;geplant&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_Actual],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMiddayControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMiddayControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Limits&amp;lt;dd&amp;gt;Inverter_Max_Power / Laden nicht vor / Start /Stop&amp;lt;br&amp;gt;MaxSOC morgens / Power morgens / Power mittags&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMidday_Inverter_Max_Power],&amp;quot;selectnumbers,1000,250,15000,0,lin&amp;quot;).&amp;quot;W&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:SpeicherMidday_MaxSOC],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; | widget([$SELF:SpeicherMidday_NotBefore],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_morning],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_start],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_midday],&amp;quot;selectnumbers,0,100,4700,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_stop],&amp;quot;time&amp;quot;).([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0)?&amp;quot;dynamisch&amp;quot;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MinSOC Steuerung&amp;lt;dd&amp;gt;fc1_Limit / Winter | Sommer /aktuell&amp;lt;/dd&amp;gt;&amp;quot;|\&lt;br /&gt;
 FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMinSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;).widget([$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;).&amp;quot;wh&amp;quot; |\&lt;br /&gt;
 widget([$SELF:SpeicherMinSOC_Winter],&amp;quot;selectnumbers,10,1,30,0,lin&amp;quot;).widget([$SELF:SpeicherMinSOC_Sommer],&amp;quot;selectnumbers,5,1,10,0,lin&amp;quot;).&amp;quot;%&amp;quot; |&amp;quot;&amp;quot;|[WR_1_API:Battery_InternControl_MinSoc].&amp;quot; %&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherCmdRepeatActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherCmdRepeatRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-11 17:23:40 SpeicherDcPowerAbs 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:13 SpeicherEntladung Automatik&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherExternTrigger none&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherMaxSOCControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOCControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOC_Actual 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMaxSOC_DayBefore 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_MinSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_Time NULL&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:38:43 SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:27 SpeicherMiddayControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMiddayControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:12 SpeicherMidday_Inverter_Max_Power 9000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-08 11:21:31 SpeicherMidday_MaxChargePowerAbs_midday 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:31 SpeicherMidday_MaxChargePowerAbs_morning 450&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:28 SpeicherMidday_MaxSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-03 09:21:27 SpeicherMidday_NotBefore 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 18:45:27 SpeicherMinSOC_Sommer 5&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:54 SpeicherMinSOC_Winter 20&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-15 08:04:40 SpeicherMinSOC_fc1_Limit 16000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:05 SpeicherTrigger entladen&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 16:10:24 SpeicherZeitEnde 19:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:41:25 SpeicherZeitStart 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 WB_1_smart_laden_before ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1 ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;&#039;&#039;&#039;disable 1&#039;&#039;&#039;&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_0_KSEM ModbusAttr 1 60 192.168.178.xyz:502 TCP&lt;br /&gt;
attr WR_0_KSEM DbLogExclude .*&lt;br /&gt;
attr WR_0_KSEM DbLogInclude Active_energy.*&lt;br /&gt;
attr WR_0_KSEM alias WR_0_KSEM&lt;br /&gt;
attr WR_0_KSEM comment Version 2021.04.07 12:00\&lt;br /&gt;
Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\&lt;br /&gt;
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\&lt;br /&gt;
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\&lt;br /&gt;
\&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\&lt;br /&gt;
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\&lt;br /&gt;
\&lt;br /&gt;
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
attr WR_0_KSEM dev-h-defPoll 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr WR_0_KSEM disable 0&lt;br /&gt;
attr WR_0_KSEM event-on-change-reading Active_energy.*,M_AC_Current_.*&lt;br /&gt;
attr WR_0_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr WR_0_KSEM icon measure_power&lt;br /&gt;
attr WR_0_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr WR_0_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr WR_0_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr WR_0_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40075-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr WR_0_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr WR_0_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr WR_0_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40084-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40086-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40087-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr WR_0_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr WR_0_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr WR_0_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40091-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40096-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr WR_0_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr WR_0_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr WR_0_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40101-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr WR_0_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr WR_0_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr WR_0_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr WR_0_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr WR_0_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h512-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr WR_0_KSEM obj-h512-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h516-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr WR_0_KSEM obj-h516-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr WR_0_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr WR_0_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr WR_0_KSEM obj-h8196-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr WR_0_KSEM obj-h8212-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr WR_0_KSEM obj-h8228-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr WR_0_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr WR_0_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_0_KSEM sortby 140&lt;br /&gt;
attr WR_0_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr WR_0_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===BYD HV Speicher (mit HTTPMOD)===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort wird mit KeyValue() (siehe oben) verwaltet.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Der BYD HV Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
 - Die erste Abfrage führt das Login durch&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num *&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
&lt;br /&gt;
======KeyValue() speichern======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline aufgerufen werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition WR_1_Speicher_1 (BYD HV)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1 HTTPMOD http://%IP-WR_1_Speicher_1%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr WR_1_Speicher_1 DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1 DbLogInclude BatteryInformation_TotalVoltage,BatteryInformation_SOC,BatteryInformation_SOC,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 authRetries 1&lt;br /&gt;
attr WR_1_Speicher_1 comment Version 2021.04.07 12:00&lt;br /&gt;
attr WR_1_Speicher_1 dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_Speicher_1 enableControlSet 0&lt;br /&gt;
attr WR_1_Speicher_1 enableCookies 1&lt;br /&gt;
attr WR_1_Speicher_1 event-on-change-reading auth_.*,Battery.*_.*,Device.*_.*,Installation.*_.*,Array_.*,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 event-on-update-reading Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr WR_1_Speicher_1 get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr WR_1_Speicher_1 get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr WR_1_Speicher_1 get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr WR_1_Speicher_1 get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr WR_1_Speicher_1 get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr WR_1_Speicher_1 get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr WR_1_Speicher_1 get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr WR_1_Speicher_1 get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr WR_1_Speicher_1 get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr WR_1_Speicher_1 get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr WR_1_Speicher_1 get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr WR_1_Speicher_1 get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr WR_1_Speicher_1 get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr WR_1_Speicher_1 get01-16Name Array_Main_Current&lt;br /&gt;
attr WR_1_Speicher_1 get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr WR_1_Speicher_1 get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr WR_1_Speicher_1 get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr WR_1_Speicher_1 get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr WR_1_Speicher_1 get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr WR_1_Speicher_1 get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr WR_1_Speicher_1 get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr WR_1_Speicher_1 get01-22Name Array_Main_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr WR_1_Speicher_1 get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-73Name Array_Main_Power&lt;br /&gt;
attr WR_1_Speicher_1 get01-80Name Array_Series_Battery&lt;br /&gt;
attr WR_1_Speicher_1 get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr WR_1_Speicher_1 get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get01Name RunData&lt;br /&gt;
attr WR_1_Speicher_1 get01RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get02Name StatisticInformation&lt;br /&gt;
attr WR_1_Speicher_1 get02RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get02URL http://%IP-WR_1_Speicher_1%/asp/StatisticInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr WR_1_Speicher_1 get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr WR_1_Speicher_1 get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03Name DeviceInformation&lt;br /&gt;
attr WR_1_Speicher_1 get03RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get03URL http://%IP-WR_1_Speicher_1%/asp/DeviceInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-37Name BatteryInformation_Power&lt;br /&gt;
attr WR_1_Speicher_1 get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr WR_1_Speicher_1 get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-9Name BatteryInformation_Current&lt;br /&gt;
attr WR_1_Speicher_1 get04DeleteIfUnmatched 1&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get04Name BatteryInformation&lt;br /&gt;
attr WR_1_Speicher_1 get04RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr WR_1_Speicher_1 get04URL http://%IP-WR_1_Speicher_1%/asp/Home.asp&lt;br /&gt;
attr WR_1_Speicher_1 get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr WR_1_Speicher_1 get05Name InstallationConfig&lt;br /&gt;
attr WR_1_Speicher_1 get05RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get05URL http://%IP-WR_1_Speicher_1%/asp/UserInfo.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Data ArrayNum=1&amp;amp;SeriesBatteryNum=4&lt;br /&gt;
attr WR_1_Speicher_1 get10Header01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 get10Header02 Referer: http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Header03 Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
attr WR_1_Speicher_1 get10Header04 Accept: text/html,application/xhtml+xml,application/xml&lt;br /&gt;
attr WR_1_Speicher_1 get10Name Test_Array&lt;br /&gt;
attr WR_1_Speicher_1 get10URL http://%IP-WR_1_Speicher_1%/goform/SetRunData&lt;br /&gt;
attr WR_1_Speicher_1 getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1 handleRedirects 1&lt;br /&gt;
attr WR_1_Speicher_1 httpVersion 1.1&lt;br /&gt;
attr WR_1_Speicher_1 icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1 reAuthRegex Unauthorized&lt;br /&gt;
attr WR_1_Speicher_1 reading01Name auth_qop&lt;br /&gt;
attr WR_1_Speicher_1 reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Name auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Name auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Name auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Regex %IP-WR_1_Speicher_1%&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Value ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1_Speicher_1&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Regex %auth_realm%&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Value auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Regex %auth_nonce%&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Value auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Regex %auth_opaque%&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Value auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Regex %auth_response%&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Value {my $NAME=&amp;quot;WR_1_Speicher_1&amp;quot;;;my $pw=KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;);; $pw =~ &#039;&amp;quot;&#039;.s/@/\\@/g.&#039;&amp;quot;&#039;;; md5_hex(md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.$pw).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:00000001:d789ea5b7e9a2377:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;));;}&lt;br /&gt;
attr WR_1_Speicher_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1 showBody 0&lt;br /&gt;
attr WR_1_Speicher_1 showError 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid01ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sid02Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid02ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid02URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sortby 121&lt;br /&gt;
attr WR_1_Speicher_1 stateFormat {sprintf(&amp;quot;Total_Charge_Energy: %.0f kWh&amp;lt;br&amp;gt;Total_Efficiency: %.1f %% Battery_EM_State: %s&amp;quot;, ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Efficiency&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;Battery_EM_State&amp;quot;,&amp;quot;&amp;quot;))}&lt;br /&gt;
attr WR_1_Speicher_1 userReadings Statistic_SpecificInformation_00_Date:Statistic_SpecificInformation_05_EndTime.* { CommandDeleteReading(undef, $NAME.&amp;quot; .*-.*&amp;quot;);;;; localtime()},\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Difference_Charge_Energy:Statistic_GeneralInformation_Total_Charge_Energy.*  {ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Efficiency:Statistic_GeneralInformation_Total_Charge_Energy.*  {round(((ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)+((ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Act_state_of_charge&amp;quot;,0)/100)*11)) / ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0))*100 , 2)}&lt;br /&gt;
attr WR_1_Speicher_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1                    BYD HV     HTTPMOD   LAN/WLAN               Speicher Details, auch über einzelne Zellen. Das kann man nur für den alten BYD HV verwenden.&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Verwendet von Plenticore zur Steuerung des Speichers&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
PV_Schedule                                   DOIF                             Startet regelmäßige Aktionen&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Das ist veraltet, da die KI_Prognose nun verwendet werden sollte.&lt;br /&gt;
   2 Stündlich von 07:00 bis 20:00&lt;br /&gt;
   2.1 WR_1_config module_1_covered                                              Schnee auf den Modulen (noch in der Entwicklungsphase)&lt;br /&gt;
   2.2 Solar_forecast() für fc0                                                  Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 zweimal am Tag&lt;br /&gt;
   3.1 Solar_forecast() für fc1                                                  Aktualisieren der fc1 Prognose&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
   4 alle 5 Minuten&lt;br /&gt;
   4.1 WR_2_API 04_auth_me                                                       Aktualisieren der Bilanz (es wird ein Event erzeugt)&lt;br /&gt;
   4.2 WR_1_API 04_auth_me                                                       Der Master Wechselrichter kommt zum Schluss, damit die SW_* readings auch von anderen&lt;br /&gt;
                                                                                 Wechselrichtern die richtigen Werte haben.&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Dies ist jetzt im WR_ctl Device enthalten&lt;br /&gt;
WR_*_config                                   DUMMY                            Konfiguration für Strings,Ausrichtung,Nennleistung,IP-Adressen,Forecast&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC               begrenzt dann morgens den MaxSOC&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday     und den MaxChargePowerAbs&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning    für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_1:Solar_middayhigh_fc0_start &amp;lt;&amp;gt; WR_1:Solar_middayhigh_fc0_stop      Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_1:Solar_middayhigh_fc0_stop                         Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====SVG====&lt;br /&gt;
In eventuellen SVGs die Device und reading Namen korrigieren&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== AW Definition PV_Schedule (DOIF)===&lt;br /&gt;
Aufgrund der Komplexität wurde die Speichersteuerung aus diesem Device entfernt und im Device PV_1_Speicher_1_ExternControl ausgelagert.&lt;br /&gt;
Weitere Neuerungen sind die Bereitstellung eines Schnee Faktors pro String für die Solar_forecast() Funktion, was aber bitte als Versuch anzusehen ist.&lt;br /&gt;
Für den Vergleich mit dem Solar_Foracast Modul wird der Forecast zwei mal aufgerufen und einmal davon ins DWD_Forecast_Test geschrieben.&lt;br /&gt;
Diese Beispiele können natürlich einfach herausgelöscht werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
\&lt;br /&gt;
   (get WR_2_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
   (get WR_1_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 5 und 21 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([05:00-21:00] and [:00])\&lt;br /&gt;
   ## Erste Versuche mit Schnee, wenn zuwenig Strom in den Modulen fließt wird ein Faktor von 0.1 gesetzt\&lt;br /&gt;
   ## WR_1_config forecast_factor_autocorrection muss auf 1 gesetzt sein, damit das berücksichtigt wird\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt;  8 &amp;amp;&amp;amp; $hour &amp;lt; 12)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_1_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_2_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 12 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_3_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_4_covered &amp;quot;.$y)})\&lt;br /&gt;
\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   ## Bei Schnee wurde der module_*_covered Faktor bereits am Vortag gesetzt.\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 regelmäßig die Bilanz aktualisieren, alle 5 Minuten außer um :00\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00])\&lt;br /&gt;
\&lt;br /&gt;
  (get WR_2_API 04_auth_me)\&lt;br /&gt;
  (get WR_1_API 04_auth_me)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])   ## 6172\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])         ## 4727\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5707\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 4717\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5241\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 3517\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState WR Status|Forecast 0|Forecast 1|Bilanz refresh&lt;br /&gt;
attr PV_Schedule comment Version 2021.04.19 12:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0,3:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4&lt;br /&gt;
attr PV_Schedule webCmdLabel Statistic :Forecast_0 :Forecast_1 :Bilanz :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc.*_.*_Rad1h,fc.*_.*_TTT,fc.*_.*_FF,fc.*_.*_Neff,fc.*_.*_R101,fc.*_.*_RRS1c,fc.*_.*_DD,fc.*_.*_N,fc.*_.*_VV,fc.*_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2022.08.20 12:00\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
FF      : Windspeed\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc.*_.*_[Rad1h|TTT|FF|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,FF,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz,fc.*_.*&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro event-on-update-reading ObsDate.*,fc.*_.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
attr Astro userReadings fc0_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
\&lt;br /&gt;
fc1_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))}&lt;br /&gt;
attr Astro verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
CREATE DEFINER=`fhemuser`@`%` PROCEDURE `dwd_load`(IN var_date DATE, IN display char(10))&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;br /&gt;
SET @date:= var_date;&lt;br /&gt;
-- die alte Tabelle löschen&lt;br /&gt;
DROP TABLE IF EXISTS dwdfull;&lt;br /&gt;
&lt;br /&gt;
-- eine neue Tabelle anlegen&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `dwdfull` (&lt;br /&gt;
  `TIMESTAMP` datetime NOT NULL,&lt;br /&gt;
  `year`   int NOT NULL,&lt;br /&gt;
  `month`  int NOT NULL,&lt;br /&gt;
  `day`    int NOT NULL,&lt;br /&gt;
  `hour`   int NOT NULL,&lt;br /&gt;
  `TTT`    float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `DD`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `VV`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `N`      float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Neff`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `R101`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `RRS1c`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunD1`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Rad1h`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAz`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAlt` float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `yield`  float  DEFAULT 0,&lt;br /&gt;
  `yield_max`  float  DEFAULT 0,&lt;br /&gt;
  `forecast`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  PRIMARY KEY (`TIMESTAMP`),&lt;br /&gt;
  INDEX (`TIMESTAMP`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=&#039;DWD Forecast&#039;;&lt;br /&gt;
&lt;br /&gt;
-- als erstes die Grundlegenden Daten mit Zeitstempeln erzeugen&lt;br /&gt;
-- Rad1h wird als erstes eingetragen&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc0 Rad1h ältere Werte eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
	 	       )&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc1 Rad1h Werte von morgen eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Mit update alle weiteren Spalten füllen&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAz&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t2  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t2.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAz&lt;br /&gt;
  SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAlt&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t6 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t6.VV&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t5.VV&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t7 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t7.DD&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t5.DD&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t8 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t8.TTT&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t5.TTT&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t9 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t9.R101&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t5.R101&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t10 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t10.N&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t5.N&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t11 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t11.RRS1c&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t5.RRS1c&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield from Plenticore with Accu&lt;br /&gt;
   -- start left join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    left JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end left join&lt;br /&gt;
   &lt;br /&gt;
   UNION  -- for left and right join&lt;br /&gt;
&lt;br /&gt;
   -- start right join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    right JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end right join&lt;br /&gt;
   &lt;br /&gt;
   -- UNION end&lt;br /&gt;
   &lt;br /&gt;
  ) t12 USING(TIMESTAMP)&lt;br /&gt;
SET tt.yield = t12.yield&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Ermittle Ertrags Maximum der letzten 30 Tage um die Prognose zu limitieren&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield_max&lt;br /&gt;
      SELECT hour,&lt;br /&gt;
             cast(max(yield) AS DECIMAL(6)) AS yield_max&lt;br /&gt;
      FROM dwdfull&lt;br /&gt;
      WHERE TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
      GROUP BY hour&lt;br /&gt;
   ) t2  USING(hour)&lt;br /&gt;
SET tt.yield_max = t2.yield_max&lt;br /&gt;
WHERE TIMESTAMP &amp;gt; @date&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
IF display = &#039;show&#039; THEN &lt;br /&gt;
  select * from dwdfull LIMIT 3000;&lt;br /&gt;
ELSE&lt;br /&gt;
  select now();&lt;br /&gt;
END IF&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose (nicht mehr aktuell)==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
====Wetter Forecast Grundlagen (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der &lt;br /&gt;
    Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deutscher Wetter Dienst (DWD) (nicht mehr aktuell)===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
====RAW Definition DWD_Forecast (nicht mehr aktuell)====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wurden einige extra Werte vom DWD abgefragt, die für das Solar_Forecast Modul verwendet werden. Dieses Modul ist noch in der experimental Phase (2021.02.23) und liefert noch nicht gleichwertige Ergebnisse. Ein Test zum vergleichen kann aber nicht schaden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc0_.*_Rad1h,fc0_.*_TTT,fc0_.*_Neff,fc0_.*_R101,fc0_.*_RRS1c,fc0_.*_DD,fc0_.*_N,fc0_.*_VV,fc0_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2023.01.05 12:40\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc0_.*_[Rad1h|TTT|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===99_myUtils.pm Funktionen===&lt;br /&gt;
====Solar_forecast() (nicht mehr aktuell)====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen, muss ein Dummy WR_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Letzte Neuerungen:&lt;br /&gt;
- IM WR_1_config kann man verbose auf &amp;gt;3 setzen und bekommt dann Log Meldungen&lt;br /&gt;
- Es wird eine Autokorrektur unterstützt. Aktivierung durch &amp;quot;setreading WR_1_config forecast_factor_autocorrection 1&amp;quot;&lt;br /&gt;
  Für die Datenbank Anbindung wird ein DbRep Device LogDBRep_PV_Forecast_SQL verwendet. Die RAW definition kommt gleich im Anschluss.&lt;br /&gt;
- Das SQL für die Berechnung des Faktors der Autokorrektur Verwendet Konfigurationsvariablen aus den DbRep Device.&lt;br /&gt;
- Bei der Autokorrektur wird auch eine Bedeckung von Schnee (Strom im String &amp;lt; 1A) berücksichtigt. (das ist noch in der Entwicklung)&lt;br /&gt;
  Dieser Faktor wird im PV_Schedule Device erzeugt und dann im &amp;quot;WR_1_config module_*_covered&amp;quot; für jeden String eingetragen.&lt;br /&gt;
  Das muss jeder individuell für seine Anlage anpassen!&lt;br /&gt;
- Für die 70% Regelung wird nun auch ein Middayhigh Trigger ermittelt und die jeweilige Start/Stop Zeit. Dies steht dann im WR_1 Device bei den Solar_* readings&lt;br /&gt;
- Es besteht auch die Möglichkeit die Solar_forecast() Funktion ohne Datenbank zu verwenden, dann ist bei den Parametern &amp;quot;none&amp;quot; zu übergeben und&lt;br /&gt;
  es muss auch die Autokorrektur abgeschaltet sein.&lt;br /&gt;
- Anstelle des Wechselrichter Devices kann nun auch ein beliebiges anderes Device angegeben werden, in das dann der Forecast geschrieben wird.&lt;br /&gt;
  Auch hier kann dann keine Autokorrektur verwendet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.06.14 15:20&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;        # Mit dieser Datenbank wird gearbeitet&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zur Kommunikation mit der LogDB verwendet und muss entsprechend konfiguriert sein&lt;br /&gt;
     my $logdevice   = &amp;quot; &amp;quot;   ;        # Das ist der Wechselrichter, oder ein anderes Device, in das die Prognose geschrieben wird&lt;br /&gt;
        $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;    # Der reading Name wird um 0 oder 1 verlängert&lt;br /&gt;
&lt;br /&gt;
     # Welcher Verbose Level ist gesetzt?&lt;br /&gt;
     my $verbose = AttrVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Gibt es einen festen Korrekturfaktor für jede Stunde?&lt;br /&gt;
     my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
     # Soll eine Autokorrektur gemacht werden? 0 = Nein 1 = Ja&lt;br /&gt;
     my $autocorrection          = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor_autocorrection&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Beim DWD wird der Wert für die Stunde erst am Ende der Stunde eingetragen&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     # Hier werden die Variablen vorbelegt&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry1h,$logentry4h,$logentryrest,$logentry,$i) = (0) x 9 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($module_covered,$Solar_Correction_Faktor_auto,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 6 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 06:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $logdbrep ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
       # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
       CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Setzen der Tageszähler und Merker&lt;br /&gt;
     $logentry            = 0 ;   # Summiert den Solar_Calculation Wert für den ganzen Tag&lt;br /&gt;
     $logentry4h          = 0 ;   # Summierung für die nächsten vier Stunden&lt;br /&gt;
     $logentryrest        = 0 ;   # Summierung für den Rest des Tages&lt;br /&gt;
&lt;br /&gt;
     my $middayhigh           = 0 ; # Ein Merker, ob das Tagesmaximum überschritten wird&lt;br /&gt;
     my $middayhigh_start     = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_stop      = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_tmp       = 0;&lt;br /&gt;
     my $middayhigh_start_tmp = 0;&lt;br /&gt;
     my $middayhigh_stop_tmp  = 0;&lt;br /&gt;
&lt;br /&gt;
     my $Inverter_Max_Power = ReadingsVal($logdevice.&amp;quot;_Speicher_1_ExternControl&amp;quot;,&amp;quot;SpeicherMidday_Inverter_Max_Power&amp;quot;,&amp;quot;unused&amp;quot;);  # Überschreiben des middayhigh&lt;br /&gt;
     if ($Inverter_Max_Power eq &amp;quot;unused&amp;quot;) {&lt;br /&gt;
       $Inverter_Max_Power = ReadingsVal($logdevice,&amp;quot;Inverter_Max_Power&amp;quot;,0) +500 ;      # Hier wird ein Durchschnittsverbrauch des Hauses aufaddiert&lt;br /&gt;
     } else {&lt;br /&gt;
       if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power manuell gesetzt&amp;quot; } ;&lt;br /&gt;
     };&lt;br /&gt;
     if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power auf &amp;quot;.$Inverter_Max_Power.&amp;quot; gesetzt&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
     # Es werden Stundenwerte von 06:00 bis 21:00 Uhr berechnet&lt;br /&gt;
     for ($i = 6; $i &amp;lt;= 21; $i++) {&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0 and $i == 6) {&lt;br /&gt;
         # Neuberechnung der stündlichen Autokorrektur Faktoren in der Datenbank. Das DbRep Device LogDBRep_PV_Forecast_SQL muss vorhanden sein.&lt;br /&gt;
         # Achtung, beim SQL muss &#039;@&#039; mit &#039;\@&#039; maskiert werden.&lt;br /&gt;
         CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking &amp;quot;.sprintf(&amp;quot;&lt;br /&gt;
               INSERT INTO history&lt;br /&gt;
                 (TIMESTAMP,DEVICE,READING,VALUE)&lt;br /&gt;
                  SELECT&lt;br /&gt;
                    TIMESTAMP,DEVICE,READING,VALUE&lt;br /&gt;
                  FROM (&lt;br /&gt;
                    SELECT&lt;br /&gt;
                      DATE_ADD(CURDATE(),INTERVAL t2.HOUR HOUR) AS TIMESTAMP,&lt;br /&gt;
                      t2.DEVICE,&lt;br /&gt;
                      \@readingname                             AS READING,&lt;br /&gt;
                      cast(if(avg(t2.FACTOR) &amp;gt; 1.6, 1.6,&lt;br /&gt;
                              avg(t2.FACTOR) ) AS DECIMAL(2,1)) AS VALUE&lt;br /&gt;
                    FROM (&lt;br /&gt;
                      SELECT * FROM (&lt;br /&gt;
                        SELECT&lt;br /&gt;
                          t1.TIMESTAMP,&lt;br /&gt;
                          t1.HOUR,&lt;br /&gt;
                          t1.DEVICE,&lt;br /&gt;
                          t1.READING,&lt;br /&gt;
                          t1.VALUE,&lt;br /&gt;
                          if(\@diff = 0,0, \@temp:=cast((t1.VALUE-\@diff) AS DECIMAL(8,2)))                                    AS DIFF,&lt;br /&gt;
                          if(((t1.VALUE+(-1*\@temp))*\@corr)=0,0, cast((t1.VALUE/(t1.VALUE+(-1*\@temp))*\@corr) AS DECIMAL(8,1))) AS FACTOR,&lt;br /&gt;
                          \@diff:=t1.VALUE                                                                                        AS curr_V&lt;br /&gt;
                        FROM (&lt;br /&gt;
                          SELECT&lt;br /&gt;
                            h.TIMESTAMP,&lt;br /&gt;
                            date(h.TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(h.TIMESTAMP) AS HOUR,&lt;br /&gt;
                            h.DEVICE,&lt;br /&gt;
                            h.READING,&lt;br /&gt;
                            h.VALUE&lt;br /&gt;
                          FROM history AS h&lt;br /&gt;
                          WHERE h.DEVICE    =  \@device&lt;br /&gt;
                            AND (h.READING  =  \@reading1 OR h.READING = \@reading2)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;gt;= DATE_SUB(DATE(now()),INTERVAL \@days DAY)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;lt;= CURDATE()&lt;br /&gt;
                            AND MINUTE(h.TIMESTAMP) = 0&lt;br /&gt;
                            AND h.VALUE &amp;gt;= 50&lt;br /&gt;
                          GROUP BY DATE,HOUR,h.READING,h.DEVICE,h.TIMESTAMP&lt;br /&gt;
                         )t1&lt;br /&gt;
                       )tx&lt;br /&gt;
                        WHERE READING != \@reading2&lt;br /&gt;
                          AND HOUR &amp;gt; 6&lt;br /&gt;
                     )t2&lt;br /&gt;
                      GROUP BY t2.HOUR,t2.DEVICE&lt;br /&gt;
                   )t3&lt;br /&gt;
                    WHERE&lt;br /&gt;
                      t3.VALUE != 0&lt;br /&gt;
                    ORDER BY TIMESTAMP&lt;br /&gt;
                    ON DUPLICATE KEY UPDATE&lt;br /&gt;
                      VALUE=t3.VALUE;&lt;br /&gt;
           &amp;quot;) # Ende sprintf()&lt;br /&gt;
         );   # Ende CommandGet()&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
       $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
       if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
         $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
&lt;br /&gt;
         $Solar_Rain = 0;&lt;br /&gt;
         for (my $r600 = $i+5; $r600 &amp;gt;= $i; $r600--) {&lt;br /&gt;
           $Solar_Rain        += ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($r600+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
         $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
         $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
         $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
         if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation.&amp;quot; W &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0).&amp;quot; J&amp;quot; } ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($cloudk ne 0) {&lt;br /&gt;
         $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
         $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($raink ne 0) {&lt;br /&gt;
         $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($tempk ne 0) {&lt;br /&gt;
         $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0) {&lt;br /&gt;
         $Solar_Correction_Faktor_auto = CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking SELECT VALUE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;Solar_Correction_Faktor_auto&#039; AND TIMESTAMP=&#039;&amp;quot;.sprintf(&amp;quot;%4d-%02d-%02d %02d:00:00&amp;quot;,$year,$mon,$mday,$i).&amp;quot;&#039;;&amp;quot;) ;&lt;br /&gt;
         if($Solar_Correction_Faktor_auto eq &amp;quot;&amp;quot;) { $Solar_Correction_Faktor_auto = 1; };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $logentry1h = 0 ;   # Summierung für eine Stunde zurücksetzen&lt;br /&gt;
&lt;br /&gt;
       # Es werden 5 Modul Ausrichtungen durchlaufen, der Name der Ausrichtung befindet sich z.B. in WR_1_config&lt;br /&gt;
       for(my $j=1;$j&amp;lt;=5;$j++){&lt;br /&gt;
         # lesen der Modul Anzahl&lt;br /&gt;
         $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
         if ($module_count[$j] ne 0) {&lt;br /&gt;
           # Für diese Ausrichtung sind Module Installiert&lt;br /&gt;
&lt;br /&gt;
           # Berechnung des Korrekturfaktors für die Modul Ausrichtung&lt;br /&gt;
           $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;factor/plain/direction       : &amp;quot;.$Solar_Plain.&amp;quot; &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) };&lt;br /&gt;
           # Berechnung der Modul Nennleistung für diese Ausrichtung&lt;br /&gt;
           $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
           # Anwendung der Korrekturfaktoren&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp   * $Solar_Correction_Cloud * $Solar_Correction_Rain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Faktor ;&lt;br /&gt;
&lt;br /&gt;
           if ($autocorrection ne 0) {&lt;br /&gt;
             # Nachsehen, ob dieser String mit Schnee bedeckt ist&lt;br /&gt;
             $module_covered = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_covered&amp;quot;,1) ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $Solar_Correction_Faktor_auto ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $module_covered ;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot;_covered             : &amp;quot;.$module_covered };&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Runden auf volle Watt Werte&lt;br /&gt;
           $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot; estimation          : &amp;quot;.$Solar_[$j] };&lt;br /&gt;
&lt;br /&gt;
           # Aufsummieren aller konfigurierter Ausrichtungen&lt;br /&gt;
           $logentry1h += $Solar_[$j] ; # Summe für eine Stunde (wird mit jedem lauf von $i wieder auf 0 gesetzt)&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe der nächsten 4 h gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour and $i &amp;lt;= $hour+3) {&lt;br /&gt;
             $logentry4h += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe für den Resttag gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour) {&lt;br /&gt;
             $logentryrest += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           $logentry += $Solar_[$j] ; # Summe für den ganzen Tag&lt;br /&gt;
&lt;br /&gt;
           # Den Forecast Wert für die aktuelle Stunde in das Wechselrichter Device schreiben&lt;br /&gt;
           if ($fc == 0 and $hour == $i) {&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;                   : &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; };&lt;br /&gt;
             CommandSetReading(undef, $logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j]) ;&lt;br /&gt;
           };&lt;br /&gt;
         };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Alle Forecast Werte für die jeweilige Stunde in die DbLog schreiben (Es wird der Cache verwendet)&lt;br /&gt;
&lt;br /&gt;
       if ( $logdb ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
         CommandSet(undef, $logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry1h.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry1h.&amp;quot;|&amp;quot;) ;&lt;br /&gt;
&lt;br /&gt;
         if ( $middayhigh == 0 and $logentry1h &amp;gt; $Inverter_Max_Power ) {&lt;br /&gt;
           $middayhigh           = 1;&lt;br /&gt;
           $middayhigh_start_tmp = $i-1;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;lt; $Inverter_Max_Power and $middayhigh_stop_tmp == 0 )  {&lt;br /&gt;
           $middayhigh_stop_tmp = $i;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;gt; $Inverter_Max_Power and $middayhigh_stop ne &amp;quot;00:00&amp;quot; )  {&lt;br /&gt;
           $middayhigh_stop_tmp = 0;                                # da war ein kurzer Einbruch, es sollte noch länger sein.&lt;br /&gt;
         };&lt;br /&gt;
         if ($middayhigh == 1 and&lt;br /&gt;
             $middayhigh_stop_tmp != 0 and&lt;br /&gt;
             $middayhigh_stop_tmp == $i ) {                                    # das Ende des Middayhigh wurde gefunden&lt;br /&gt;
&lt;br /&gt;
           $middayhigh_tmp = $middayhigh_stop_tmp - $middayhigh_start_tmp;&lt;br /&gt;
           if ( $middayhigh_tmp &amp;gt; 4 )  {                                       # das Middayhigh wird zu lang&lt;br /&gt;
             if ($verbose &amp;gt;= 3 ) {                                             # die bisherigen Zeiten ausgeben&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp) ;&lt;br /&gt;
             }&lt;br /&gt;
             $middayhigh_tmp       = round(($middayhigh_tmp/4)-0.2 ,0);        # die Rundung der Zeit zum Abziehen etwas verschieben&lt;br /&gt;
             $middayhigh_start_tmp = $middayhigh_start_tmp + $middayhigh_tmp;  # es wird um ganze Stunden verkürzt&lt;br /&gt;
             $middayhigh_stop_tmp  = $middayhigh_stop_tmp  - $middayhigh_tmp;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) {                                              # melde die Verkürzung&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;         : verkürzt um &amp;quot;.($middayhigh_tmp *2).&amp;quot; Stunden&amp;quot;;&lt;br /&gt;
             }&lt;br /&gt;
           };&lt;br /&gt;
           $middayhigh_start = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
           $middayhigh_stop  = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp);&lt;br /&gt;
           if ($verbose &amp;gt;= 3) {                                                # gib die finalen Zeiten aus&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.$middayhigh_start;&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.$middayhigh_stop ;&lt;br /&gt;
           }&lt;br /&gt;
         };&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ; # setz die Zeiten im Device&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Sobald mindestens ein String configuriert ist sollen diese Werte, der aktuellen Stunde, in das Wechselrichter Device geschrieben werden&lt;br /&gt;
       if ($fc == 0 and $hour == $i and $module_count[1] ne 0) {&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry1h) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Auch die Solar_Calculation jeder einzelnen Stunde wird als reading in das Wechselrichter Device geschrieben&lt;br /&gt;
       CommandSetReading(undef, sprintf(&amp;quot;%s %s_%02d %d&amp;quot;,$logdevice,$reading,$i,$logentry1h)) ;&lt;br /&gt;
&lt;br /&gt;
       # Für die Fehlersuche kommen noch einige Informationen ins Log&lt;br /&gt;
       if ($verbose &amp;gt;= 3) {&lt;br /&gt;
         Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Cloud                  : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;cloudk                       : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Cloud       : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Rain                   : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;raink                        : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Rain        : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Temp                   : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;tempk                        : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Temp        : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor      : &amp;quot;.$Solar_Correction_Faktor ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor_auto : &amp;quot;.$Solar_Correction_Faktor_auto ;&lt;br /&gt;
         Log 3, &amp;quot;Forecast,Hour,Estimation 1h  : &amp;quot;.$fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$logentry1h ;&lt;br /&gt;
       };&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Die Summe der nächsten 4 Stunden in das Wechselrichter Device schreiben&lt;br /&gt;
     if ($fc == 0) {&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_4h &amp;quot;.$logentry4h) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_rest &amp;quot;.$logentryrest) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_day &amp;quot;.$logentry) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $middayhigh == 0 ) {    # Auf Defaults zurücksetzen&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.02.28 17:00&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    my $verbose     = AttrVal(&amp;quot;Astro&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = CommandGet(undef, &amp;quot;Astro text SunAz &amp;quot;.$time) ;&lt;br /&gt;
    my $elevation   = CommandGet(undef, &amp;quot;Astro text SunAlt &amp;quot;.$time) ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain time             : &amp;quot;.$time;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain azimuth          : &amp;quot;.$azimuth;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain elevation        : &amp;quot;.$elevation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain orientation      : &amp;quot;.$orientation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain angle            : &amp;quot;.$angle;&lt;br /&gt;
    };&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.1798) {&lt;br /&gt;
      if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_Forecast_SQL (nicht mehr aktuell)====&lt;br /&gt;
Dieses Device war vormals das LogDBRep_PV_Forecast_SQL , es wird jedoch nun mehrfach verwendet und wurde deshalb umbenannt. Das LogDBRep_PV_Forecast_SQL kann gelöscht werden.&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
Für die Solar_forecast() Funktion wurden hier SQL Variablen Definiert, die für die Autokorrektur verwendet werden:&lt;br /&gt;
- @days ist die Anzahl der Tage, über die ein stündlicher, durchschnitts Korrektur Faktor berechnet wird.&lt;br /&gt;
- @corr ermöglicht es diesen Faktor nochmals zu verändern &amp;lt;1 dämpft, &amp;gt;1 verstärkt&lt;br /&gt;
- @device ist der Plenticore Wechselrichter&lt;br /&gt;
- @reading1 ist die reale DC Leistung ohne die Batterie, hier wird &#039;&#039;&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;&#039;&#039; für die Schwarm Implementierung verwendet.&lt;br /&gt;
- @reading2 wird der Basisname der readings im WR_1 Device&lt;br /&gt;
- @readingname wird der reading Name des Korrekturfaktors.&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
Durch die Erweiterung zum Schwarm mit mehreren AC-Quellen wurde die Variable @reading1 verändert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_Forecast_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL allowDeletion 1&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL room System&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdVars SET @days:=3, @corr:=0.7, @diff:=0, @temp:=0, @device:=&#039;WR_1&#039;, @reading1:=&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;, @reading2:=&#039;Solar_Calculation_fc0&#039;, @readingname:=&#039;Solar_Correction_Faktor_auto&#039; ;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solar Forcast Tests (nicht mehr aktuell)===&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Astro Device Test====&lt;br /&gt;
Bei diesem Test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() Test (nicht mehr aktuell)====&lt;br /&gt;
Diese Funktion kann man folgendermaßen testen. Für Log Meldungen muss man im &#039;&#039;&#039;Astro Device verbose auf 3&#039;&#039;&#039; oder größer stellen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung, das Dach hätte demnach also Süd/West Lage.&lt;br /&gt;
&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann Folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:51:27.312 3: Solar_plain azimuth          : 210.6&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain elevation        : 0.49916224518291&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain orientation      : 0.185004188774085&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain angle            : 0.785395141022061&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain factor           : 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurückgeliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_forecast() Test (nicht mehr aktuell)====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
Bei gesetztem &amp;quot;&#039;&#039;&#039;attr Astro verbose 3&#039;&#039;&#039;&amp;quot; erscheinen hier ebenfalls die Astro Log Informationen.&lt;br /&gt;
Durch setzen von &amp;quot;&#039;&#039;&#039;attr WR_1_config verbose 3&#039;&#039;&#039;&amp;quot; bekommt man die Log Meldungen vom Sorar_forecast()&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&lt;br /&gt;
generische Verwendung ohne DbLog/DbRep: &#039;&#039;&#039;Das Astro Device muss &amp;quot;Astro&amp;quot; heißen und das DWD Device muss &amp;quot;DWD_Forecast&amp;quot; heißen!!&#039;&#039;&#039;&lt;br /&gt;
{Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;&amp;lt;beliebiges Device&amp;gt;&amp;quot;,&amp;quot;&amp;lt;prefix für die readings&amp;gt;_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,[0|1])}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann solche Blöcke, die man zusammenhängend betrachten sollte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power manuell gesetzt&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power auf 7000 gesetzt&lt;br /&gt;
2021.04.07 15:57:23.932 3: Solar_SolarRadiation         : 17 W 60.00 J        &amp;lt;&amp;lt;&amp;lt; vom DWD gelieferte Prognose in Watt und Joul&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain azimuth          : 80.2                &amp;lt;&amp;lt;&amp;lt; Astro Informationen&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain orientation      : -0.171041608489249&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain factor           : 0.001               &amp;lt;&amp;lt;&amp;lt; Die Funktion ist noch außerhalb des Gültigkeitsbereiches&lt;br /&gt;
2021.04.07 15:57:23.977 3: factor/plain/direction       : 0.001 40/-90     &lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1_covered             : 1                   &amp;lt;&amp;lt;&amp;lt; Ein Faktor für die Schneebedeckung&lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1 estimation          : 0                   &amp;lt;&amp;lt;&amp;lt; Die erwartete Leistung liegt bei 0 Watt&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:23.991 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2_covered             : 1&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain orientation      : -1.94183189053337&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.002 3: factor/plain/direction       : 0.001 40/0&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.013 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.020 3: Solar_SolarRadiation         : 17                  &amp;lt;&amp;lt;&amp;lt; Rad1h ist 70 Watt&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Cloud                  : 70                  &amp;lt;&amp;lt;&amp;lt; 70 % Abdeckung des Himmels durch Wolken&lt;br /&gt;
2021.04.07 15:57:24.021 3: cloudk                       : -0.45 0             &amp;lt;&amp;lt;&amp;lt; Werte der Korrekturfunktion für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Correction_Cloud       : 0.685               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Rain                   : 152&lt;br /&gt;
2021.04.07 15:57:24.022 3: raink                        : -0.2 0&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Correction_Rain        : 0.696               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Regen&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Temp                   : 10.7                &amp;lt;&amp;lt;&amp;lt; Erwartete Temperatur an den Modulen (Schätzung) &lt;br /&gt;
2021.04.07 15:57:24.023 3: tempk                        : -0.39 25&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Temp        : 1.056               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für die Modultemperatur&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor      : 1                   &amp;lt;&amp;lt;&amp;lt; Fester Korrekturfaktor aus WR_1_config &lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor_auto : 0.5                 &amp;lt;&amp;lt;&amp;lt; Korrekturfaktor aus der Datenbank Berechnung der letzten Tage &lt;br /&gt;
2021.04.07 15:57:24.024 3: Forecast,Hour,Estimation 1h  : 0 7 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Forecast Basiseinstellung (nicht mehr aktuell)===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät WR_1_config von einer Ost/Süd/West Anlage mitgeliefert (setstate). Es werden bis zu 5 Strings unterstützt.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auch &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät WR_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch zusätzliche Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Berücksichtigung von Temperatur, Bewölkung und Regen (nicht mehr aktuell)===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das Ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
Durch die Autokorrektur ist nun auch ein Schnee Faktor dazu gekommen. Dieser wird im PV_Schedule Device &amp;quot;berechnet&amp;quot; :-) und und in das PV_1_config geschrieben. Bei aktivierter Autokorrektur wird dieser dann berücksichtigt.&lt;br /&gt;
=====Temperatur (nicht mehr aktuell)=====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Wolken und Regen (nicht mehr aktuell)=====&lt;br /&gt;
Aus den DWD_Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken Einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
===wunderground===&lt;br /&gt;
Dieser Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das kann dann als aktueller Wert in den Diagrammen angezeigt werden und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mit einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
&lt;br /&gt;
===RAW Definition Wetter_&amp;lt;Wohnort&amp;gt;===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;JSON&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;builtIn&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;datasource&amp;quot;: &amp;quot;-- Grafana --&amp;quot;,&lt;br /&gt;
        &amp;quot;enable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;iconColor&amp;quot;: &amp;quot;rgba(0, 211, 255, 1)&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Annotations &amp;amp; Alerts&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;dashboard&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;editable&amp;quot;: true,&lt;br /&gt;
  &amp;quot;gnetId&amp;quot;: null,&lt;br /&gt;
  &amp;quot;graphTooltip&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;id&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;links&amp;quot;: [],&lt;br /&gt;
  &amp;quot;panels&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P value&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;: &amp;quot;rgb(90, 90, 90)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid value&amp;quot;: &amp;quot;rgb(250, 250, 250)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_AC_Active_P&amp;quot;: &amp;quot;dark-orange&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P&amp;quot;: &amp;quot;semi-dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 0&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: false,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:78&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:79&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:80&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 10,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:81&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:82&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:83&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 5,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS &#039;SW_Total_DC_P&#039;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_grid\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_grid&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_PV\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_PV&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_Battery\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_Battery&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Actual_Battery_charge_usable_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Actual_Battery_charge_usable_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_AC_Active_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_AC_Active_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;A&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Leistungsbezug&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Heizung&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Heizung value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Pool&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Waschmaschine&amp;quot;: &amp;quot;light-red&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 12&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hideEmpty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;hideZero&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: true,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;connected&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true,&lt;br /&gt;
          &amp;quot;steppedLine&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P_Max&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  abs(avg(value)) AS \&amp;quot;Heizung\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;StromZaehler_Heizung&#039; AND\n  READING = &#039;SMAEM1901401955_Saldo_Wirkleistung&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;StromZaehler_Heizung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SMAEM1901401955_Saldo_Wirkleistung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Pool\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly02&#039; AND\n  READING = &#039;Power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly02&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Waschmaschine\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly03&#039; AND\n  READING = &#039;power&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly03&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Brunnen\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Brunnen&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Shaun\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_1&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Shaun&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hauptverbraucher&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0&amp;quot;: &amp;quot;super-light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0 value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1 value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East value&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South value&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West&amp;quot;: &amp;quot;light-purple&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West value&amp;quot;: &amp;quot;super-light-purple&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 13,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 24&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: null,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc0\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc0&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc1\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc1&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc1&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_sumOfAllPVInputs\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_sumOfAllPVInputs&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_DC_Sum&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Solar_Calculation\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_Ost\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_Ost&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_Ost&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_Ost&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_Sued\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_Sued&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_Sued&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_Sued&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Forecast/Prognose&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;16000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;refresh&amp;quot;: &amp;quot;5m&amp;quot;,&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 27,&lt;br /&gt;
  &amp;quot;style&amp;quot;: &amp;quot;dark&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [],&lt;br /&gt;
  &amp;quot;templating&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: []&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;time&amp;quot;: {&lt;br /&gt;
    &amp;quot;from&amp;quot;: &amp;quot;now-1d/d&amp;quot;,&lt;br /&gt;
    &amp;quot;to&amp;quot;: &amp;quot;now-1d/d&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timepicker&amp;quot;: {&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;refresh_intervals&amp;quot;: [&lt;br /&gt;
      &amp;quot;5s&amp;quot;,&lt;br /&gt;
      &amp;quot;10s&amp;quot;,&lt;br /&gt;
      &amp;quot;30s&amp;quot;,&lt;br /&gt;
      &amp;quot;1m&amp;quot;,&lt;br /&gt;
      &amp;quot;5m&amp;quot;,&lt;br /&gt;
      &amp;quot;15m&amp;quot;,&lt;br /&gt;
      &amp;quot;30m&amp;quot;,&lt;br /&gt;
      &amp;quot;1h&amp;quot;,&lt;br /&gt;
      &amp;quot;2h&amp;quot;,&lt;br /&gt;
      &amp;quot;1d&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timezone&amp;quot;: &amp;quot;utc&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;PV_Anlage_1&amp;quot;,&lt;br /&gt;
  &amp;quot;uid&amp;quot;: &amp;quot;W-Y51Dmgk&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: 105&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit SVG==&lt;br /&gt;
Die Diagramme werden bei mir nicht mehr weiterentwickelt, da ich auf Grafana umgestiegen bin. Sie stehen hier nur noch als Beispiele für den Anfang.&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Total_PV_P_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_Battery::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB WR_1:SW_Actual_battery_charge_usable_P::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_Max::&lt;br /&gt;
#LogDB WR_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:max_month_SW_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_&amp;lt;Wohnort&amp;gt;_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB WR_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_sumOfAllPVInputs::&lt;br /&gt;
#LogDB WR_1:Solar_Calculation::&lt;br /&gt;
#LogDB WR_1:Solar_East::&lt;br /&gt;
#LogDB WR_1:Solar_South::&lt;br /&gt;
#LogDB WR_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power_(sumOfAllPVInputs)&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV_Perl (DOIF Modul) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 1                                   ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                     ## Die LWP ist aus\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]           ## Die maximale Laufzeit der LWP ist noch nicht erreicht\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## Das Maximum des PV-Modus ist noch nicht erreicht\&lt;br /&gt;
     and [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]   ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : LWP on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;LWP_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;PV_Modus_Ein_LWP();;set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;)&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : LWP on for manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : LWP off after manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]          ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : LWP off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; 100                              ## es soll noch eine Reserve bleiben\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : LWP off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;gt; 0                                  ## läuft eine Wartezeit\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 5                                  ## läuft die Wartezeit bald ab\&lt;br /&gt;
     and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot;\&lt;br /&gt;
      and [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe läuft&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer LWP &amp;quot;.get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;)};;\&lt;br /&gt;
    del_Exec(&amp;quot;LWP_Ein_timer&amp;quot;);;                                           ## Die LWP wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
## Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_1_LWP_Nachheizen_WW\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [[$SELF:TimeEnd]]                                               ## Am Ende der möglichen PV Steuerung\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt;= 48                             ## wenn das Wasser noch nicht im Sollbereich ist\&lt;br /&gt;
     and\&lt;br /&gt;
        (   [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]        ## Die maximale Laufzeit der LWP/Tag ist noch nicht erreicht\&lt;br /&gt;
         or [LWP_Counter:countsPerDay] eq 0)                             ## oder die LWP ist noch gar nicht gelaufen\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_LWP_Nachheizen_WW&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP on for water heating&amp;quot;};;\&lt;br /&gt;
                                                                         ## Es wird die Soll Temperatur um die Hysterese angehoben \&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget &amp;quot;.(ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,48)+4));;\&lt;br /&gt;
                                                                         ## Das zurücksetzen auf den Standard von 50° erfolgt generell beim Abschalten\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Hohe Priorität im Winter für die LWP\&lt;br /&gt;
## Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_2_LWP_Prioritaet_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [WR_1:SW_Total_PV_P_reserve] &amp;gt;= 2000                            ## es besteht jedoch noch eine Reserve und der\&lt;br /&gt;
     and [shelly02:power_0] &amp;gt; 800                                        ## Pool wird gerade aufgeheizt, was im Winter auch in der Nacht passiert\&lt;br /&gt;
     and [WR_1:Act_state_of_charge] &amp;gt; 60                                 ## Der Speicher sollte schon 60 % gefüllt sein\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## und die WW Temperatur noch unter 60°\&lt;br /&gt;
     and [$SELF:LWP_Priority] eq &amp;quot;frei&amp;quot;                                  ## Aber nur einmal am Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_LWP_Prioritaet_An&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_2 : LWP Priorität&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___LWP_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
        or [$SELF:LWP_Status] eq &amp;quot;manuell&amp;quot;\&lt;br /&gt;
       )\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimeMin]\&lt;br /&gt;
     and ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___LWP_Ende&amp;quot;                           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 05__ : LWP run finished&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Priorität für LWP wieder frei geben, damit einmal am Tag der PV-Modus verwendet werden kann\&lt;br /&gt;
##\&lt;br /&gt;
06___LWP_Prioritaet_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [23:55]\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;06___LWP_Prioritaet_Reset&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 06__ : LWP Priorität frei&amp;quot;};;\&lt;br /&gt;
     set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;frei&amp;quot;);;                                 ## Der PV-Modus darf wieder verwendet weden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## In der Überganszeit wird die Heizung kurz vor der PV-Zeit wieder ein geschaltet\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_1_Heizung_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeStartHeizung]]                                        ## Einschalten der Heizung, damit aus dem Puffer nachgeheizt wird 02:03\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_1_Heizung_An&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_1 : LWP Heizung Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHeating Auto&amp;quot;);;                  ## Die Heizungssteuerung erfolgt wieder Automatisch\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_2_Heizung_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeEndHeizung]]                                          ## Abschalten der Heizung, damit der Puffer für morgens Heizreserve hat\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_2_Heizung_Aus&amp;quot;                        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 07_2 : LWP Heizung aus&amp;quot;};;\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;Heizung opModeHeating Off&amp;quot;);;                     ## Die Heizung wird komplett abgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
   if (    [WR_1:Solar_Calculation_fc1_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] ## Auch morgen ist das Wetter schlecht\&lt;br /&gt;
       and [Heizung:averageAmbientTemperature] &amp;lt;= 5.6 ) {                ## Die Heizgrenze ist schon ziemlich tief\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungWinter]);;    ## Im Winter bis in die Morgenstunden den Accu sparen\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 07_2 : Parameter: &amp;quot;.[WR_1:Solar_Calculation_fc1_day].&amp;quot; &amp;lt; &amp;quot;.[WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit].&amp;quot; and &amp;quot;.[Heizung:averageAmbientTemperature].&amp;quot; &amp;lt;= 5.6&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungUebergang]);; ## Bei schönerem Wetter erst später Heizen\&lt;br /&gt;
     }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_2 : TimeStartHeizung switched to &amp;quot;.[$SELF:TimeStartHeizung]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 15°\&lt;br /&gt;
##\&lt;br /&gt;
07_3_Heizung_WZ_15_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_3_Heizung_WZ_15_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_3 : Heizung WZ 15 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 15&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 22°\&lt;br /&gt;
##\&lt;br /&gt;
07_4_Heizung_WZ_22_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_4_Heizung_WZ_22_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_4 : Heizung WZ 22 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 22&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung aus\&lt;br /&gt;
##\&lt;br /&gt;
07_5_Warmwasser_aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_5_Warmwasser_aus&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_5 : LWP Warmwasser aus&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Off&amp;quot;);;                  ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation inactive&amp;quot;);;                      ## Zirkulation ebenfalls abschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung auf Automatik\&lt;br /&gt;
##\&lt;br /&gt;
07_6_Warmwasser_an\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_6_Warmwasser_an&amp;quot;                      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_6 : LWP Warmwasser Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Auto&amp;quot;);;                 ## Die Warmwassersteuerung erfolgt wieder automatisch\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation active&amp;quot;);;                        ## Zirkulation wieder einschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_LWP() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP on&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 60.0&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;verwendet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_LWP() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 50.0&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr LWP_PV_Perl DbLogExclude .*&lt;br /&gt;
attr LWP_PV_Perl DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV_Perl alias LWP_PV_Perl&lt;br /&gt;
attr LWP_PV_Perl comment Version 2023.01.18 09:00&lt;br /&gt;
attr LWP_PV_Perl disable 0&lt;br /&gt;
attr LWP_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV_Perl icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV_Perl room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV_Perl sortby 411&lt;br /&gt;
attr LWP_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|::ReadingsTimestamp(&amp;quot;Heizung&amp;quot;,&amp;quot;counterHeatQTotal&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Status / LWP Status / Brauchwasser&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,04_1_LWP_Nachheizen_WW,04_2_LWP_Prioritaet_An,05___LWP_Ende,06___LWP_Prioritaet_Reset,07_1_Heizung_An,07_2_Heizung_Aus,07_3_Heizung_WZ_15_Grad,07_4_Heizung_WZ_22_Grad,07_5_Warmwasser_aus,07_6_Warmwasser_an&amp;quot;) |[Heizung:opStateHeatPump1].&amp;quot; &amp;quot;.[Heizung:opStateHeatPump2]|[Heizung:opStateHeatPump3]|FUNC_Status([Heizung:hotWaterTemperature],47,&amp;quot;orange&amp;quot;,[Heizung:hotWaterTemperature],&amp;quot;green&amp;quot;,[Heizung:hotWaterTemperature],53,&amp;quot;red&amp;quot;,[Heizung:hotWaterTemperature]).&amp;quot; °C&amp;quot;\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;PV-Modus / Heiz-Modus / Winter, Übergangszeit Heiz Start/Ende&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;PV-Modus:&amp;lt;br&amp;gt;&amp;quot;.[$SELF:LWP_Priority].&amp;quot; / &amp;quot;.(([$SELF:LWP_Status] ne &amp;quot;Aus&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039;)|&amp;quot;Heizung: &amp;quot;.[Heizung:opModeHeating].&amp;quot;&amp;lt;br&amp;gt;Warmwasser: &amp;quot;.[Heizung:opModeHotWater]|widget([$SELF:TimeStartHeizungWinter],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartHeizungUebergang],&amp;quot;time&amp;quot;)|[$SELF:TimeStartHeizung].widget([$SELF:TimeEndHeizung],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;Statistiken&amp;quot;|&amp;quot;Zähler&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Information&amp;quot;|&amp;quot;Wert&amp;quot;\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;EVU&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[EVU_StromZaehler:Strom_Status-02])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;LWP/KWL&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung_Zaehler])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHeating])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Warmwasser&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHotWater])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Photovoltaik&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQPool])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQTotal])\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 23:55:00 LWP_Priority frei&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-29 15:37:06 LWP_Status Aus&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 12:21:48 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 3000&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 2250&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-25 19:00:12 RunTimeMin 2400&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:55:35 RunTimePerDay 28800&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:37 TimeEnd 15:05&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 13:24:01 TimeEndHeizung 18:35&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:19 TimeStart 11:30&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 18:35:00 TimeStartHeizung 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:37:59 TimeStartHeizungUebergang 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:34:08 TimeStartHeizungWinter 02:05&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-31 12:05:34 ui_command_1 ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.54&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP&lt;br /&gt;
attr shelly01 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 412&lt;br /&gt;
attr shelly01 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung_Zaehler&amp;quot;,0));;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Wärmepumpe Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly01 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{4}(\.[0-9]{1})*$ StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{1,3}(\.[0-9]{1})*$&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter comment Version 2021.01.09 11:16&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 413&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39050</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39050"/>
		<updated>2024-01-24T15:13:23Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* 2. aWattar */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWATTar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind.&lt;br /&gt;
* Die bisherige Berechnung mit Stand 20240123 wäre wie folgt: round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39040</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39040"/>
		<updated>2024-01-23T16:57:36Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* EVU_aWATTar_connect  RAW Device */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind.&lt;br /&gt;
* Die bisherige Berechnung mit Stand 20240123 wäre wie folgt: round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39039</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39039"/>
		<updated>2024-01-23T16:56:29Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* EVU_aWATTar_connect  RAW Device */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind.&lt;br /&gt;
* Die bisherige Berechnung mit Stand 20240123 wäre wie folgt: round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03+1.785)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39038</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39038"/>
		<updated>2024-01-23T16:55:30Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Vorrausetzungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind.&lt;br /&gt;
* Die bisherige Berechnung mit Stand 20240123 wäre wie folgt: round(($val+$val*0.03+1.785)*1.19,2)&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39037</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39037"/>
		<updated>2024-01-23T16:49:54Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Vorrausetzungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind.&lt;br /&gt;
* Die bisherige Berechnung wäre wie folgt: round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39036</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39036"/>
		<updated>2024-01-23T16:44:11Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind. ( das ist bisher noch nicht im Device umgesetzt )&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.\&lt;br /&gt;
\&lt;br /&gt;
https://api.awattar.de/v1/marketdata&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round(($val+$val*0.03)*1.19,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round(($val+$val*0.03)*1.19/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39035</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39035"/>
		<updated>2024-01-23T15:51:11Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind. ( das ist bisher noch nicht im Device umgesetzt )&lt;br /&gt;
&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39034</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39034"/>
		<updated>2024-01-23T15:50:15Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das EVU_Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
=== EVU_aWATTar_connect ===&lt;br /&gt;
Das EVU_aWATTar_connect fragt mit HTTPMOD die aWATTar API Webseite ab. Es werden keine Live Verbrauchdaten geliefert.&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind. ( das ist bisher noch nicht im Device umgesetzt )&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39033</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39033"/>
		<updated>2024-01-23T15:46:37Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* Für die Berechnung der tatsächlichen Kosten benötigt man seine lokalen fix Kosten, die je nach Region unterschiedlich sind. ( das ist bisher noch nicht im Device umgesetzt )&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39032</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39032"/>
		<updated>2024-01-23T15:43:41Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
#    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
#      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
#    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_date&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_aWATTar_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_aWATTar_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_aWATTar_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39029</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39029"/>
		<updated>2024-01-23T14:27:18Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* EVU_aWATTar_connect  RAW Device */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00\&lt;br /&gt;
\&lt;br /&gt;
Achtung, momentan werden nur die Börsenpreise ohne die fix Kosten dargestellt.&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
 \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
  $price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39028</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39028"/>
		<updated>2024-01-23T12:53:00Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. aWattar ==&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
&lt;br /&gt;
==== EVU_aWATTar_connect  RAW Device ====&lt;br /&gt;
Momentan fragt das EVU_aWattar_connect lediglich die aktuellen Preise des Tages ab. Die readings sind an die des EVU_Tibber_connect angelehnt, um im weiteren Verlauf evetuell ein gemeinsames Device für die Anzeige und Steuerung zu erarbeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_aWATTar_connect HTTPMOD https://api.awattar.de/v1/marketdata/current.yaml 0&lt;br /&gt;
attr EVU_aWATTar_connect DbLogExclude .*&lt;br /&gt;
attr EVU_aWATTar_connect comment Version 2024.01.23 13:00&lt;br /&gt;
attr EVU_aWATTar_connect enableControlSet 1&lt;br /&gt;
attr EVU_aWATTar_connect get01-15Name fc0_max&lt;br /&gt;
attr EVU_aWATTar_connect get01-15OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-1Name current_date&lt;br /&gt;
attr EVU_aWATTar_connect get01-22Name fc0_med&lt;br /&gt;
attr EVU_aWATTar_connect get01-22OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-29Name fc0_avg&lt;br /&gt;
attr EVU_aWATTar_connect get01-29OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-36Name current_price&lt;br /&gt;
attr EVU_aWATTar_connect get01-36OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01-8Name fc0_min&lt;br /&gt;
attr EVU_aWATTar_connect get01-8OExpr round($val,2)&lt;br /&gt;
attr EVU_aWATTar_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get01RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get01Regex date_now: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|price_low: ([0-9]+[0-9\.]+)|price_high: ([0-9]+[0-9\.]+)|price_median: ([0-9]+[0-9\.]+)|price_average: ([0-9]+[0-9\.]+)|price_current: ([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get01URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get02-10Name fc0_09_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-10OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-11Name fc0_10_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-11OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-12Name fc0_11_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-12OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-13Name fc0_12_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-13OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-14Name fc0_13_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-14OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-15Name fc0_14_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-15OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-16Name fc0_15_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-16OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-17Name fc0_16_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-17OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-18Name fc0_17_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-18OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-19Name fc0_18_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-19OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-1Name fc0_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-1OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-20Name fc0_19_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-20OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-21Name fc0_20_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-21OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-22Name fc0_21_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-22OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-23Name fc0_22_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-23OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-24Name fc0_23_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-24OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-2Name fc0_01_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-2OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-3Name fc0_02_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-3OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-4Name fc0_03_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-4OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-5Name fc0_04_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-5OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-6Name fc0_05_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-6OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-7Name fc0_06_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-7OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-8Name fc0_07_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-8OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02-9Name fc0_08_total&lt;br /&gt;
attr EVU_aWATTar_connect get02-9OExpr round($val/100,4)&lt;br /&gt;
attr EVU_aWATTar_connect get02FollowGet 01_priceInfo&lt;br /&gt;
attr EVU_aWATTar_connect get02Name 02_priceDay&lt;br /&gt;
attr EVU_aWATTar_connect get02RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get02Regex (?&amp;lt;=abs_[0-9]{2}_amount: )([0-9]+[0-9\.]+)&lt;br /&gt;
attr EVU_aWATTar_connect get02URL https://api.awattar.de/v1/marketdata/current.yaml&lt;br /&gt;
attr EVU_aWATTar_connect get03-1Name fc3_00_startsAt&lt;br /&gt;
attr EVU_aWATTar_connect get03-1OExpr POSIX::strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,localtime(substr($val,0,10)))&lt;br /&gt;
attr EVU_aWATTar_connect get03-4Name fc3_00_total&lt;br /&gt;
attr EVU_aWATTar_connect get03-4OExpr round($val/1000,4)&lt;br /&gt;
attr EVU_aWATTar_connect get03Name 02_priceAll&lt;br /&gt;
attr EVU_aWATTar_connect get03RegOpt g&lt;br /&gt;
attr EVU_aWATTar_connect get03Regex &amp;quot;start_timestamp&amp;quot;: (\d{10})|&amp;quot;marketprice&amp;quot;: (\d*\.\d*)&lt;br /&gt;
attr EVU_aWATTar_connect get03URL https://api.awattar.de/v1/marketdata?start=1701990000000&amp;amp;end=1702159200000&lt;br /&gt;
attr EVU_aWATTar_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_aWATTar_connect icon sani_pump&lt;br /&gt;
attr EVU_aWATTar_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_aWATTar_connect sortby 213&lt;br /&gt;
attr EVU_aWATTar_connect userReadings fc0_trigger_price:fc0_avg.* {\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
my $price_level = round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_avg&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_min&amp;quot;,0))/2 + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_min&amp;quot;,0) , 1);;\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls aWATTar zu teuer wird\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
  my $price_level_battery = round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_avg&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
  if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
    $price_level = $price_level_battery\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc0_trigger_price.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,1).&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_aWATTar_connect verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39027</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39027"/>
		<updated>2024-01-23T11:24:46Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39026</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39026"/>
		<updated>2024-01-23T11:24:16Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
[[Bild:Screenshot 2024-01-23 122115.png|mini|900px|rechts|EVU_Tibber_connect]]&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Datei:Screenshot_2024-01-23_122115.png&amp;diff=39025</id>
		<title>Datei:Screenshot 2024-01-23 122115.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Datei:Screenshot_2024-01-23_122115.png&amp;diff=39025"/>
		<updated>2024-01-23T11:22:12Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39024</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39024"/>
		<updated>2024-01-23T11:18:41Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* KeyValue() Funktion in der 99_myUtils */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der ~/FHEM/99_myUtils.pm ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39023</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39023"/>
		<updated>2024-01-23T11:18:03Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils.pm .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39022</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39022"/>
		<updated>2024-01-23T11:17:44Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
&lt;br /&gt;
=== Vorrausetzungen ===&lt;br /&gt;
* FHEM mit einer installierten MySQL DbLog (FileLog wird nicht untertsützt)&lt;br /&gt;
* KeyValue() (wird hier beschrieben)&lt;br /&gt;
* Tibber Pulse Lesekopf auf dem digitalen EVU Zähler&lt;br /&gt;
* Man sollte bereits Tibber Kunde sein, da ansonsten nur Demo Daten abgrufen werden können&lt;br /&gt;
&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39021</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39021"/>
		<updated>2024-01-23T11:13:25Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39020</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39020"/>
		<updated>2024-01-23T11:12:26Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39019</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39019"/>
		<updated>2024-01-23T11:10:52Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect Beschreibung ====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LogDBRep_EVU_Tibber_connect_SQL RAW Device ====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
Das Device dient der Anzeige und Steuerung des EVU_Tibber_connect Devices.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39018</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39018"/>
		<updated>2024-01-23T11:09:11Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect Beschreibung ====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
Dieses DbRep Device dient der Verbindung zur MySQL DbLog. Die SQL SELECT Statements wertden im EVU_Tibber_connect Device generiert und über dieses Device in der MySQL DbLog ausgeführt. Der Name des Devices wird ebenfalls generiert und liegt somit fest.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL room System&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_EVU_Tibber_connect_SQL timeout 20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39017</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39017"/>
		<updated>2024-01-23T11:03:38Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* EVU_Tibber_connect Beschreibung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect Beschreibung ====&lt;br /&gt;
Das Device EVU_Tibber_connect dient der Verbindung zur Tibber API. Zusätzlich wird für die Abfrege der Live Daten innerhalb der userReadings eine WebSocket Verbindung zu Tibber aufgebaut. Tibber stellt jeweils gegen 14:00 Uhr die Daten für den nächsten Tag bereit, wodurch von 00:00 - 14:00 Uhr diese Information im EVU_Tibber_connect noch nicht angezeigt werden kann.&lt;br /&gt;
Das Device arbeitet über die userReadings mit einem MySQL DbRep Device, was somit eine MySQL DbLog Verwendung im FHEM voraussetzt. &#039;&#039;&#039;Die Verwendung von FileLog ist nicht unterstützt!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39015</id>
		<title>Strombörse</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Stromb%C3%B6rse&amp;diff=39015"/>
		<updated>2024-01-23T09:18:54Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Seite beinhaltet Informationen für die Anbindung von Energieversorgungsunternehmen (EVU), die ihre Preise nach der Strombörse z.B. im Stundenrythmus anbieten.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel wären da:&lt;br /&gt;
&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=130407.0 Tibber - im Forum]&lt;br /&gt;
# [https://forum.fhem.de/index.php?topic=135906.0 aWattar - im Forum]&lt;br /&gt;
&lt;br /&gt;
Diese Wiki Seite ist noch in Bearbeitung!!!&lt;br /&gt;
&lt;br /&gt;
== 1. Tibber mit Tibber Pulse ==&lt;br /&gt;
Eine momentan verbreitete Methode zur Anbindung an Tibber ist ein Lesekopf auf dem EVU Zähler, der als &amp;quot;Tibber Pulse&amp;quot; vertrieben wird. Damit wird ein bestehender digitaler EVU Zähler ausgelesen und die Werte per LAN zu Tibber gesendet. Über eine API bei Tibber können dann die Verbrauchswerte und Kosten, sowie ein Live Stream (WebSocket) abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Die im folgenden beschriebenen Beispiel Devices bieten die oben genannte Abfrage der API mit WebSocket und HTTPMOD. Das EVU_Tibber Device dient der Darstellung und Steuerung.&lt;br /&gt;
=== EVU_Tibber_connect ===&lt;br /&gt;
Das Tibber_connect fragt mit HTTPMOD statistiken auf der Tibber API Webseite ab. Zusätzlich wurde in den userReadings die WebSocket Verbindung für die Live Daten integriert.&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Websocket Die WebSocket Verbindung wurde leicht angepasst von hier übernommen.]&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130407.msg1298863.html?sslRedirect#msg1298863 Im Forum wurde dies hier bearbeitet.]&lt;br /&gt;
&lt;br /&gt;
==== Verwendete Module ====&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DOIF&lt;br /&gt;
* KeyValue()&lt;br /&gt;
&lt;br /&gt;
==== Ablage der homeID und des Tokens ====&lt;br /&gt;
Eine Verbindung zur Tibber API mit den &#039;&#039;&#039;tatsächlichen Preise bekommen nur Kunden&#039;&#039;&#039;, ansonsten kann man eine Demo mit Kosten in Schwedischen Kronen testweise abfragen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel Device kann man seine homeID und sein Token entweder als Attribut ablegen, oder man macht einen Eintrag im KeyStore von FHEM, wodurch man nicht so leicht ausversehen seine Daten im Forum Posted.&lt;br /&gt;
&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
===== Beispiel KeyValue() =====&lt;br /&gt;
&#039;&#039;&#039;Achtung, der KeyValue ist kein Schutz für Passwort oder Keys!&#039;&#039;&#039;&lt;br /&gt;
Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im FHEM Device oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
====== KeyValue() Funktion in der 99_myUtils ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablegen der homeID und des Token ======&lt;br /&gt;
In der FHEM Kommandozeile legt man seinen Daten wie folgt im KeyValue ab. Hier wären als Beispiel der Demo Zugang von Tibber.&lt;br /&gt;
Das &amp;quot;read&amp;quot; ist dann auch direkt der erste Test, bevor man weiter macht.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}&lt;br /&gt;
&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Beispiel Attribut für homeID und Token =====&lt;br /&gt;
Oder, sobald das EVU_Tibber_connect Device erstellt wurde, als Attribut.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr EVU_Tibber_connect ws_homeId 96a14971-525a-4420-aae9-e5aedaa129ff&lt;br /&gt;
attr EVU_Tibber_connect ws_myId 96a14971-525a-4420-aae9-e5aedaa129ff          &amp;lt;&amp;lt;&amp;lt;&amp;lt; Dies kann wohl eine frei gewählte ID sein, was hier der Einfachheithalber gleich der homeId gesetzt wurde.&lt;br /&gt;
attr EVU_Tibber_connect ws_token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect Beschreibung====&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber_connect RAW Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0&lt;br /&gt;
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL&lt;br /&gt;
attr EVU_Tibber_connect DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*&lt;br /&gt;
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \&lt;br /&gt;
https://developer.tibber.com/explorer\&lt;br /&gt;
\&lt;br /&gt;
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\&lt;br /&gt;
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\&lt;br /&gt;
\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;,&amp;quot;5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE&amp;quot;)}\&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;,&amp;quot;96a14971-525a-4420-aae9-e5aedaa129ff&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\&lt;br /&gt;
setreading EVU_Tibber compensation_grid &amp;lt;Eure Einspeisevergütung&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
    (fc_avg - fc_min)  /2 + fc_min\&lt;br /&gt;
\&lt;br /&gt;
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\&lt;br /&gt;
    (fc_avg - compensation_grid) *0.85&lt;br /&gt;
attr EVU_Tibber_connect disable 0&lt;br /&gt;
attr EVU_Tibber_connect enableControlSet 1&lt;br /&gt;
attr EVU_Tibber_connect get01-1Name current_currency&lt;br /&gt;
attr EVU_Tibber_connect get01-2Name current_level&lt;br /&gt;
attr EVU_Tibber_connect get01-3Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get01-4Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get01-4OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get01Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get01Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current&lt;br /&gt;
attr EVU_Tibber_connect get01Name 01_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get02-10Name fc0_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-12Name fc0_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-14Name fc0_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-16Name fc0_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-18Name fc0_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-1Name current_date&lt;br /&gt;
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-20Name fc0_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-22Name fc0_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-24Name fc0_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-26Name fc0_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-28Name fc0_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-2Name current_price&lt;br /&gt;
attr EVU_Tibber_connect get02-2OExpr $val *100&lt;br /&gt;
attr EVU_Tibber_connect get02-30Name fc0_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-32Name fc0_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-34Name fc0_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-36Name fc0_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-38Name fc0_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-40Name fc0_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-42Name fc0_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-44Name fc0_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-46Name fc0_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-48Name fc0_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-4Name fc0_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-50Name fc0_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-52Name fc1_00_total&lt;br /&gt;
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-54Name fc1_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-56Name fc1_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-58Name fc1_03_total&lt;br /&gt;
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-60Name fc1_04_total&lt;br /&gt;
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-62Name fc1_05_total&lt;br /&gt;
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-64Name fc1_06_total&lt;br /&gt;
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-66Name fc1_07_total&lt;br /&gt;
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-68Name fc1_08_total&lt;br /&gt;
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-6Name fc0_01_total&lt;br /&gt;
attr EVU_Tibber_connect get02-70Name fc1_09_total&lt;br /&gt;
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-72Name fc1_10_total&lt;br /&gt;
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-74Name fc1_11_total&lt;br /&gt;
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-76Name fc1_12_total&lt;br /&gt;
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-78Name fc1_13_total&lt;br /&gt;
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-80Name fc1_14_total&lt;br /&gt;
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-82Name fc1_15_total&lt;br /&gt;
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-84Name fc1_16_total&lt;br /&gt;
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-86Name fc1_17_total&lt;br /&gt;
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-88Name fc1_18_total&lt;br /&gt;
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-8Name fc0_02_total&lt;br /&gt;
attr EVU_Tibber_connect get02-90Name fc1_19_total&lt;br /&gt;
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-92Name fc1_20_total&lt;br /&gt;
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-94Name fc1_21_total&lt;br /&gt;
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-96Name fc1_22_total&lt;br /&gt;
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02-98Name fc1_23_total&lt;br /&gt;
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt&lt;br /&gt;
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get02Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get02Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo&lt;br /&gt;
attr EVU_Tibber_connect get02Name 02_priceAll&lt;br /&gt;
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get03-1Name nodes_00_00_from&lt;br /&gt;
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-4Name nodes_00_01_from&lt;br /&gt;
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03-7Name nodes_00_02_from&lt;br /&gt;
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get03-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get03Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get03Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get03Name 03_consumption_hour&lt;br /&gt;
attr EVU_Tibber_connect get03RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get03Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get04-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-1Name nodes_24_00_from&lt;br /&gt;
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get04-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get04Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get04Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get04Name 04_consumption_hour_24&lt;br /&gt;
attr EVU_Tibber_connect get04RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get04Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get05AutoNumLen 4&lt;br /&gt;
attr EVU_Tibber_connect get05Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}&amp;quot;}&lt;br /&gt;
attr EVU_Tibber_connect get05Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get05JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100&lt;br /&gt;
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon&lt;br /&gt;
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname&lt;br /&gt;
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname&lt;br /&gt;
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse&lt;br /&gt;
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-3Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort&lt;br /&gt;
attr EVU_Tibber_connect get06-5Name Adresse_06_Land&lt;br /&gt;
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude&lt;br /&gt;
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude&lt;br /&gt;
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz&lt;br /&gt;
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail&lt;br /&gt;
attr EVU_Tibber_connect get06Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get06Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get06JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get06Name 06_address&lt;br /&gt;
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect get07-10Name nodes_24_03_from&lt;br /&gt;
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-11OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-13Name nodes_24_04_from&lt;br /&gt;
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-14OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-16Name nodes_24_05_from&lt;br /&gt;
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-17OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-19Name nodes_24_06_from&lt;br /&gt;
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-20OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-22Name nodes_24_07_from&lt;br /&gt;
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-23OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-25Name nodes_24_08_from&lt;br /&gt;
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-26OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-28Name nodes_24_09_from&lt;br /&gt;
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-29OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-2Name features_id&lt;br /&gt;
attr EVU_Tibber_connect get07-2OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-31Name nodes_24_10_from&lt;br /&gt;
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-32OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-34Name nodes_24_11_from&lt;br /&gt;
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-35OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-37Name nodes_24_12_from&lt;br /&gt;
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-38OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-40Name nodes_24_13_from&lt;br /&gt;
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-41OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-43Name nodes_24_14_from&lt;br /&gt;
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-44OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-46Name nodes_24_15_from&lt;br /&gt;
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-47OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-49Name nodes_24_16_from&lt;br /&gt;
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-4Name nodes_24_01_from&lt;br /&gt;
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-50OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-52Name nodes_24_17_from&lt;br /&gt;
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-53OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-55Name nodes_24_18_from&lt;br /&gt;
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-56OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-58Name nodes_24_19_from&lt;br /&gt;
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-59OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-5OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-61Name nodes_24_20_from&lt;br /&gt;
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-62OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-64Name nodes_24_21_from&lt;br /&gt;
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-65OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-67Name nodes_24_22_from&lt;br /&gt;
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-68OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-70Name nodes_24_23_from&lt;br /&gt;
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-71OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07-7Name nodes_24_02_from&lt;br /&gt;
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)&lt;br /&gt;
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost&lt;br /&gt;
attr EVU_Tibber_connect get07-8OExpr ($val ne &amp;quot;0&amp;quot; and $val ne &amp;quot;null&amp;quot;)? round($val,4) : $val&lt;br /&gt;
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption&lt;br /&gt;
attr EVU_Tibber_connect get07Data { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {id features{realTimeConsumptionEnabled} } } }&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect get07Header01 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect get07JSON data_viewer_home&lt;br /&gt;
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled&lt;br /&gt;
attr EVU_Tibber_connect get07RegOpt g&lt;br /&gt;
attr EVU_Tibber_connect get07Regex \{&amp;quot;from&amp;quot;:&amp;quot;([\d+-]+T[\d+:]+\.000[+-][\d+:]+)&amp;quot;,&amp;quot;cost&amp;quot;:(null|\d+\.\d+|0),&amp;quot;consumption&amp;quot;:(null|\d+\.\d+|0)\}&lt;br /&gt;
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql&lt;br /&gt;
attr EVU_Tibber_connect group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber_connect icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber_connect replacement01Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement01Regex %%token%%&lt;br /&gt;
attr EVU_Tibber_connect replacement01Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect replacement02Mode expression&lt;br /&gt;
attr EVU_Tibber_connect replacement02Regex %%homeID%%&lt;br /&gt;
attr EVU_Tibber_connect replacement02Value {KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;)}&lt;br /&gt;
attr EVU_Tibber_connect requestData { &amp;quot;query&amp;quot;: &amp;quot;{viewer {home(id:\&amp;quot;%%homeID%%\&amp;quot;) {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}&amp;quot; }&lt;br /&gt;
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json&lt;br /&gt;
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%&lt;br /&gt;
attr EVU_Tibber_connect room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber_connect showBody 1&lt;br /&gt;
attr EVU_Tibber_connect showError 1&lt;br /&gt;
attr EVU_Tibber_connect sortby 313&lt;br /&gt;
attr EVU_Tibber_connect timeout 30&lt;br /&gt;
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device already open&amp;quot; if (defined($devState));;\&lt;br /&gt;
    \&lt;br /&gt;
    # establish connection to websocket\&lt;br /&gt;
    # format must also include portnumber if a path is to be specified\&lt;br /&gt;
    $hash-&amp;gt;{DeviceName} = AttrVal($name, &amp;quot;ws_websocketURL&amp;quot;, &amp;quot;wss:echo.websocket.org:443&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # special headers needed for Tibber, see also Developer Tools in Browser\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Sec-WebSocket-Protocol&#039;} = &#039;graphql-transport-ws&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Host&#039;} = &#039;websocket-api.tibber.com&#039;;;\&lt;br /&gt;
    $hash-&amp;gt;{header}{&#039;Origin&#039;} = &#039;https://developer.tibber.com&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    # callback function when &amp;quot;select()&amp;quot; signals data for us\&lt;br /&gt;
    # websocket Ping/Pongs are treated in DevIo but still call this function\&lt;br /&gt;
    $hash-&amp;gt;{directReadFn} = sub () {\&lt;br /&gt;
        my $hash = $defs{$name};;\&lt;br /&gt;
        \&lt;br /&gt;
        # we can read without closing the DevIo, because select() signalled data\&lt;br /&gt;
        my $buf = DevIo_SimpleRead($hash);;\&lt;br /&gt;
        \&lt;br /&gt;
        # if read fails, close device\&lt;br /&gt;
        if(!defined($buf)) {\&lt;br /&gt;
            DevIo_CloseDev($hash);;\&lt;br /&gt;
            $buf = &amp;quot;not_connected&amp;quot;;;\&lt;br /&gt;
        }\&lt;br /&gt;
        \&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data: &amp;gt;&amp;gt;&amp;gt;$buf&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
        \&lt;br /&gt;
        # only update our reading if buffer is not empty and if last update is older than minInterval\&lt;br /&gt;
        if ($buf ne &amp;quot;&amp;quot;) {\&lt;br /&gt;
            my $websocketDataAge = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 3600);;\&lt;br /&gt;
            my $minInterval = AttrVal($name, &amp;quot;ws_minInterval&amp;quot;, 0);;\&lt;br /&gt;
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\&lt;br /&gt;
            \&lt;br /&gt;
            readingsBeginUpdate($hash);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if ($isNext &amp;amp;&amp;amp; $websocketDataAge &amp;gt; $minInterval);;\&lt;br /&gt;
            readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;$buf&amp;quot;) if (!$isNext);;\&lt;br /&gt;
            readingsEndUpdate($hash, 1);;\&lt;br /&gt;
            #Log(3, &amp;quot;$name:$reading: websocket data written to reading&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
    };;\&lt;br /&gt;
    \&lt;br /&gt;
    # open DevIo websocket\&lt;br /&gt;
    DevIo_OpenDev($hash, 0, undef, sub(){\&lt;br /&gt;
        my ($hash, $error) = @_;;\&lt;br /&gt;
        return &amp;quot;$error&amp;quot; if ($error);;\&lt;br /&gt;
        \&lt;br /&gt;
        my $token = AttrVal($name, &amp;quot;ws_token&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
           $token = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_token&amp;quot;) if ($token eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
        DevIo_SimpleWrite($hash, &#039;{&amp;quot;type&amp;quot;:&amp;quot;connection_init&amp;quot;,&amp;quot;payload&amp;quot;:{&amp;quot;token&amp;quot;:&amp;quot;&#039;.$token.&#039;&amp;quot;}}&#039;, 2);;\&lt;br /&gt;
    });;\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
    #Log(3, &amp;quot;$name:$reading: websocket data cleared in reading&amp;quot;);;\&lt;br /&gt;
      \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_disconnect:ws_cmd:.disconnect {\&lt;br /&gt;
    Log(3, &amp;quot;$name: disconnect&amp;quot;);;\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    RemoveInternalTimer($hash);;\&lt;br /&gt;
    DevIo_SimpleRead($hash);;\&lt;br /&gt;
    DevIo_CloseDev($hash);;\&lt;br /&gt;
\&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onDisconnect {\&lt;br /&gt;
    my $myState = ReadingsVal($name, &amp;quot;state&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    my $myData = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    return if ($myState ne &amp;quot;disconnected&amp;quot; and $myData ne &amp;quot;not_connected&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
	## timer callback function, called after a few seconds to initiate a reconnect\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
		\&lt;br /&gt;
		# only re-connect if device is not connected\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1) if (!defined($devState));;\&lt;br /&gt;
	};;\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	# wait a random time before reconnect (exponential backoff TBD):\&lt;br /&gt;
	my $rwait = int(rand(200)) + 30;;\&lt;br /&gt;
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set cmd to a new value, informs user and allows to retrigger when timer expires\&lt;br /&gt;
	my $hash = $defs{$name};;\&lt;br /&gt;
	readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;reconnect attempt in $rwait seconds&amp;quot;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onTimeout:ws_websocketData:.* {\&lt;br /&gt;
	#re-establish websocket connection if no data received in the past ten minutes\&lt;br /&gt;
	#but only if our reading &amp;quot;ws_cmd&amp;quot; was not set to the value &amp;quot;disconnect&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: websocket data triggert ws_onTimeout&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#timeout in seconds when the connection is considered dead\&lt;br /&gt;
	my $timeoutTime = 600;;\&lt;br /&gt;
	\&lt;br /&gt;
	# function to execute when timeout expired\&lt;br /&gt;
	# defining the function here in the userReading, allows us to insert variables directly\&lt;br /&gt;
	my $timerFunction = sub() {\&lt;br /&gt;
		my ($arg) = @_;;\&lt;br /&gt;
		my $hash = $defs{$name};;\&lt;br /&gt;
		my $rCmd = ReadingsVal($name, &amp;quot;ws_cmd&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
		my $age  = ReadingsAge($name, &amp;quot;ws_websocketData&amp;quot;, 0);;\&lt;br /&gt;
		\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer triggered &amp;gt;&amp;gt;$arg&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		#do not do anything further if disconnect is on purpose\&lt;br /&gt;
		if ( $rCmd eq &amp;quot;disconnect&amp;quot; ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_cmd was set to disconnect&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		# for whatever reason, we triggered to soon (80%)\&lt;br /&gt;
		if ( $age &amp;lt; $timeoutTime*0.8 ) {\&lt;br /&gt;
			Log(3, &amp;quot;$name: ws_websocketData is not outdated&amp;quot;);;\&lt;br /&gt;
			return;;\&lt;br /&gt;
		}\&lt;br /&gt;
		\&lt;br /&gt;
		DevIo_CloseDev($hash);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer closed DevIo...&amp;quot;);;\&lt;br /&gt;
		\&lt;br /&gt;
		readingsSingleUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;connect&amp;quot;, 1);;\&lt;br /&gt;
		Log(3, &amp;quot;$name: onTimeoutTimer set ws_cmd to value &#039;connect&#039;&amp;quot;);;\&lt;br /&gt;
	};;\&lt;br /&gt;
\&lt;br /&gt;
        #Log(3, &amp;quot;$name:$reading: onTimeout function defined&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
	#remove/cancel previous timers, because we got fresh data and countdown starts again\&lt;br /&gt;
	RemoveInternalTimer($name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	#set timer to expire and execute function defined above, give special arg as identifier\&lt;br /&gt;
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.&#039;Timer&#039;);;\&lt;br /&gt;
	\&lt;br /&gt;
	return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\&lt;br /&gt;
    #ws_websocketData contains the string &amp;quot;connection_ack&amp;quot;\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # do not proceed if connection is lost\&lt;br /&gt;
    my $hash = $defs{$name};;\&lt;br /&gt;
    my $devState = DevIo_IsOpen($hash);;\&lt;br /&gt;
    return &amp;quot;Device not open&amp;quot; if (!defined($devState));;\&lt;br /&gt;
\&lt;br /&gt;
    readingsBulkUpdate($hash, &amp;quot;ws_cmd&amp;quot;, &amp;quot;got connection ack&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    my $homeId = AttrVal($name, &amp;quot;ws_homeId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $homeId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($homeId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    my $myId = AttrVal($name, &amp;quot;ws_myId&amp;quot;, &amp;quot;???&amp;quot;);;\&lt;br /&gt;
       $myId = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;EVU_Tibber_connect_homeID&amp;quot;) if ($myId eq &amp;quot;???&amp;quot;);;\&lt;br /&gt;
    \&lt;br /&gt;
    # build the query, do it in pieces, the comma at the end caused perl errors\&lt;br /&gt;
    # so we put it together in this not very elegant way\&lt;br /&gt;
    my $json = &#039;{ &amp;quot;id&amp;quot;:&amp;quot;&#039;. $myId .&#039;&amp;quot;, &amp;quot;type&amp;quot;:&amp;quot;subscribe&amp;quot;&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;payload&amp;quot;:{&#039;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;variables&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;extensions&amp;quot;:{}&#039;.&amp;quot;, &amp;quot;;;\&lt;br /&gt;
    $json .= &#039;&amp;quot;query&amp;quot;:&amp;quot;subscription { liveMeasurement( homeId: \&amp;quot;&#039;.$homeId.&#039;\&amp;quot; ) &#039;;;\&lt;br /&gt;
    #$json .= &#039;{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower &#039;;;\&lt;br /&gt;
    $json .= &#039;powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction &#039;;;\&lt;br /&gt;
    $json .= &#039;powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}&amp;quot;&#039;;;\&lt;br /&gt;
    $json .= &#039;}}&#039;;;\&lt;br /&gt;
    \&lt;br /&gt;
    #send the string via websocket as ASCII\&lt;br /&gt;
    Log(3, &amp;quot;$name:$reading: sending JSON: &amp;gt;&amp;gt;&amp;gt;$json&amp;lt;&amp;lt;&amp;lt;&amp;quot;);;\&lt;br /&gt;
    DevIo_SimpleWrite($hash, $json, 2);;\&lt;br /&gt;
        \&lt;br /&gt;
    return POSIX::strftime(&amp;quot;%H:%M:%S&amp;quot;,localtime(time()));;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\&lt;br /&gt;
    #websocketData contains next-live-measurement-data\&lt;br /&gt;
    my $val = ReadingsVal($name, &amp;quot;ws_websocketData&amp;quot;, &amp;quot;{}&amp;quot;);;\&lt;br /&gt;
    my %res = %{json2nameValue($val, undef, undef, &amp;quot;payload_data_liveMeasurement.*&amp;quot;)};;\&lt;br /&gt;
    \&lt;br /&gt;
    my $ret = &amp;quot;got values for:\n&amp;quot;;;\&lt;br /&gt;
    foreach my $k (sort keys %res) {\&lt;br /&gt;
        $ret .= &amp;quot;$k\n&amp;quot;;;\&lt;br /&gt;
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\&lt;br /&gt;
    }\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_00_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 2;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_00_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:nodes_24_00_cost.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
my $tmp = 0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 0;; $loop_last &amp;lt;= 23;; $loop_last++) {\&lt;br /&gt;
  $timestamp = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_from&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_cost&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_24_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_last).&amp;quot;_consumption&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $tmp = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
if ($tmp eq &amp;quot;null&amp;quot;) {\&lt;br /&gt;
  $timestamp = $tmp\&lt;br /&gt;
}\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\&lt;br /&gt;
my ($timestamp,$value) = 2x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_last = 1;; $loop_last &amp;lt;= 300;; $loop_last += 3) {\&lt;br /&gt;
\&lt;br /&gt;
  $timestamp =  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+2),&amp;quot;null&amp;quot;);; # timestamp\&lt;br /&gt;
  $timestamp =~ s/T/ /g ;;\&lt;br /&gt;
  $timestamp =  substr($timestamp,0,19);;\&lt;br /&gt;
  $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last+1),&amp;quot;null&amp;quot;);;  # cost\&lt;br /&gt;
\&lt;br /&gt;
  if ( $value ne &amp;quot;&amp;quot; ) {\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
# print $timestamp.&amp;quot; &amp;quot;.$value.&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
    # Eintragen der Kosten für die Stunde\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_cost&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    # Eintragen des Verbrauchs für die Stunde\&lt;br /&gt;
    $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;05_consumption_hourly_100-&amp;quot;.sprintf(&amp;quot;%04d&amp;quot;,$loop_last),&amp;quot;null&amp;quot;);;  # consumption\&lt;br /&gt;
    $value = round($value,4);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;nodes_consumption&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
              ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
  }\&lt;br /&gt;
} # end for\&lt;br /&gt;
\&lt;br /&gt;
$timestamp;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_avg:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_avg&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_min:nodes_TIMESTAMP.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
} else {\&lt;br /&gt;
  ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_min&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_cost_max:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Ermittlung des maximal Wertes\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_TIMESTAMP&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND TIMESTAMP &amp;gt;= curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;nodes_cost_max&amp;quot;,&amp;quot;null&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Monats Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
nodes_consumption_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Verbrauches\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_consumption&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_avg:current_price.* {\&lt;br /&gt;
## Berechnung des durchschnitt Wertes\&lt;br /&gt;
  my $fc_avg = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    if (AttrVal(&amp;quot;$NAME&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$NAME cmd_1  : Tibber Daten für fc1 sind bereits da&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {                                          ## Summe  berechnen\&lt;br /&gt;
        $fc_avg += ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
        } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_med:current_price.* {\&lt;br /&gt;
## Berechnung des median Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT\&lt;br /&gt;
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, floor(1+((count(VALUE)-1) / 2)))  , &#039;,&#039;, -1))\&lt;br /&gt;
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), &#039;,&#039;, ceiling(1+((count(VALUE)-1) / 2))), &#039;,&#039;, -1))\&lt;br /&gt;
                     )/2 *100\&lt;br /&gt;
             AS DECIMAL(4,2))\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND (   READING=&#039;fc0_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW(), &#039;%Y-%m-%d 00:00:00&#039;)\&lt;br /&gt;
                     OR READING=&#039;fc1_total&#039; AND TIMESTAMP &amp;gt;= DATE_FORMAT(NOW() + INTERVAL 1 DAY, &#039;%Y-%m-%d 00:00:00&#039;) ) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_min:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_min = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;lt; $fc_min) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_min = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_max:current_price.* {\&lt;br /&gt;
##  Ermittlung des minimal Wertes\&lt;br /&gt;
  my $fc_max = 0;;\&lt;br /&gt;
  my $fc_tmp = 0;;\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist bereits da\&lt;br /&gt;
    $fc = 1;;\&lt;br /&gt;
  } # end if\&lt;br /&gt;
\&lt;br /&gt;
    for (my $j=0;;$j&amp;lt;=$fc;;$j++){\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=23;;$k++) {\&lt;br /&gt;
        $fc_tmp = ReadingsVal(&amp;quot;$NAME&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j,$k),0);;\&lt;br /&gt;
  \&lt;br /&gt;
        if (($fc_tmp &amp;gt; $fc_max) or ($j == 0 and $k == 0)) {\&lt;br /&gt;
          $fc_max = $fc_tmp;;\&lt;br /&gt;
        }\&lt;br /&gt;
      } # end $k\&lt;br /&gt;
    } # end $j\&lt;br /&gt;
\&lt;br /&gt;
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_price:fc_avg.* {\&lt;br /&gt;
## fc_trigger_price:[fc_avg|compensation_grid].* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_min = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_min&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\&lt;br /&gt;
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\&lt;br /&gt;
  \&lt;br /&gt;
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0) != 0 ) {\&lt;br /&gt;
    my $price_level_battery = round( ($fc_avg - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;compensation_grid&amp;quot;,0)) *0.85 , 1) ;;\&lt;br /&gt;
    if ( $price_level &amp;gt; $price_level_battery ) {\&lt;br /&gt;
      $price_level = $price_level_battery;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger:fc0_trigger_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,100)  &amp;lt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_start:fc_trigger_price.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_stop:fc0_trigger_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_price = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_price&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_stop = $fc_trigger_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;lt; $fc_trigger_price ) {\&lt;br /&gt;
        $fc_trigger_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_trigger_max:fc_avg.* {\&lt;br /&gt;
  my $fc_avg = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_avg&amp;quot;,0);;\&lt;br /&gt;
  my $fc_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_max&amp;quot;,0);;\&lt;br /&gt;
\&lt;br /&gt;
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\&lt;br /&gt;
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\&lt;br /&gt;
  \&lt;br /&gt;
$price_level;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger_max Fensters\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
  my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = $hour;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $fc = 0;;\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
     # wechsel zum nächsten Tag\&lt;br /&gt;
     if ( $loop_hour == 23 and $fc == 0 ) {\&lt;br /&gt;
       $fc = 1;;\&lt;br /&gt;
       $loop_hour = -1;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc0_trigger_max:fc0_trigger_max_stop.* {\&lt;br /&gt;
\&lt;br /&gt;
  # Setzen des maximum Triggers für die aktuelle Stunde\&lt;br /&gt;
  if ( ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;current_price&amp;quot;,0)  &amp;gt; ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) ) {\&lt;br /&gt;
    return(&amp;quot;on&amp;quot;)\&lt;br /&gt;
  } else {\&lt;br /&gt;
    return(&amp;quot;off&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_start:fc_trigger_max.* {\&lt;br /&gt;
  if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
    # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour)) ;;\&lt;br /&gt;
      }\&lt;br /&gt;
    } # end  for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
  return(&amp;quot;null&amp;quot;);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc1_trigger_max_stop:fc0_trigger_max_start.* {\&lt;br /&gt;
  my $loop_hour = 0;;\&lt;br /&gt;
  my $fc_trigger_max = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc_trigger_max&amp;quot;,0) /100;;\&lt;br /&gt;
\&lt;br /&gt;
  # Ermitteln des nächsten Trigger Fensters\&lt;br /&gt;
  my $fc_trigger_max_start = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_trigger_max_start&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\&lt;br /&gt;
\&lt;br /&gt;
  if ( $fc_trigger_max_start ne &amp;quot;null&amp;quot; ) {\&lt;br /&gt;
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\&lt;br /&gt;
    my $fc_total = 0;;\&lt;br /&gt;
\&lt;br /&gt;
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $fc_total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$loop_hour).&amp;quot;_total&amp;quot;,0);;\&lt;br /&gt;
      if ( $fc_total &amp;gt; $fc_trigger_max ) {\&lt;br /&gt;
        $fc_trigger_max_stop = sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour) ;;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return(sprintf(&amp;quot;%02d:00&amp;quot;,$loop_hour));;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
    } # end for loop_hour\&lt;br /&gt;
  }\&lt;br /&gt;
 \&lt;br /&gt;
  return($fc_trigger_max_stop);;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_day:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Tages Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND date(TIMESTAMP) = curdate() ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_month:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des monats Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate())\&lt;br /&gt;
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
total_cost_year:nodes_TIMESTAMP.* {\&lt;br /&gt;
## Berechnung des Jahres Wertes\&lt;br /&gt;
::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\&lt;br /&gt;
           FROM history\&lt;br /&gt;
           WHERE DEVICE=&#039;&amp;quot;.$NAME.&amp;quot;&#039;\&lt;br /&gt;
             AND READING=&#039;nodes_cost&#039;\&lt;br /&gt;
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;&amp;quot;) ;;\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
fc_DbLog:fc0_00_total.* {\&lt;br /&gt;
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\&lt;br /&gt;
\&lt;br /&gt;
for (my $loop_fc = 0;; $loop_fc &amp;lt;= 1;; $loop_fc++) {\&lt;br /&gt;
  $loop_fc_next = $loop_fc +1;;\&lt;br /&gt;
  $date = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
  if ($date ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
    $date =~ /([\d+-]+)/;; $date = $1 ;;\&lt;br /&gt;
    for (my $loop_hour = 0;; $loop_hour &amp;lt;= 23;; $loop_hour++) {\&lt;br /&gt;
      $hour = sprintf(&amp;quot;%02d&amp;quot;,$loop_hour);;\&lt;br /&gt;
      $timestamp = $date.&amp;quot; &amp;quot;.$hour.&amp;quot;:00:00&amp;quot;;;\&lt;br /&gt;
      $value = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_&amp;quot;.$hour.&amp;quot;_total&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
      ::CommandGet(undef, &amp;quot;LogDBRep_&amp;quot;.$NAME.&amp;quot;_SQL sqlCmdBlocking\&lt;br /&gt;
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\&lt;br /&gt;
                          VALUES(&#039;&amp;quot;.$timestamp.&amp;quot;&#039;,&#039;$NAME&#039;,&#039;Tibber&#039;,&#039;fc&amp;quot;.$loop_fc.&amp;quot;_total&#039;,&#039;&amp;quot;.$value.&amp;quot;&#039;)\&lt;br /&gt;
                        ON DUPLICATE KEY UPDATE\&lt;br /&gt;
                          VALUE=&#039;&amp;quot;.$value.&amp;quot;&#039;;;&amp;quot;) ;;\&lt;br /&gt;
    }\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) eq ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;fc&amp;quot;.$loop_fc_next.&amp;quot;_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;)) {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc&amp;quot;.$loop_fc_next.&amp;quot;_.*&amp;quot;);;\&lt;br /&gt;
    }\&lt;br /&gt;
  } else {\&lt;br /&gt;
      fhem(&amp;quot;deletereading $NAME fc1_.*&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
ReadingsTimestamp(&amp;quot;$NAME&amp;quot;,&amp;quot;fc0_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
}&lt;br /&gt;
attr EVU_Tibber_connect verbose 0&lt;br /&gt;
attr EVU_Tibber_connect ws_minInterval 54&lt;br /&gt;
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== EVU_Tibber RAW Device ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod EVU_Tibber DOIF ## Startup Befehle für den WebSocket vom EVU_Tibber_connect\&lt;br /&gt;
init\&lt;br /&gt;
{ \&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : ▶️  EVU_Tibber init&amp;quot;);;\&lt;br /&gt;
  fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd connect&amp;quot;);; \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 0   WebSocket  : ▶️  EVU_Tibber_connect start Websocket&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
  Log(0, &amp;quot;$SELF 0   init       : 🏁 EVU_Tibber init done&amp;quot;);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## EVU_Tibber_connect start/stop WebSocket\&lt;br /&gt;
EVU_Tibber_connect_ws\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
#    or  [$SELF:ui_command_2]                                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    and [$SELF:ui_command_2] ne &amp;quot;---&amp;quot;\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    fhem(&amp;quot;setreading EVU_Tibber_connect ws_cmd &amp;quot;.[?$SELF:ui_command_2]);; \&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_2&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 1 Scheduling für das Abholen von Tibber Daten\&lt;br /&gt;
1_EVU_Tibber_PriceInfo\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;1_EVU_Tibber_PriceInfo&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Preis für die aktuelle Stunde\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 03_consumption_hour&amp;quot;);;         ## Kosten der letzen drei Stunden\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 1   PriceInfo  : Abfrage von Tibber&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Scheduling für das Abholen der Tibber Preise\&lt;br /&gt;
2_EVU_Tibber_PriceAll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;2_EVU_Tibber_PriceAll&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 02_priceAll&amp;quot;);;\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 2   priceAll   : Abfrage von Tibber für den nächsten Tag&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Erstellen des Diagramms im uiTable\&lt;br /&gt;
3_EVU_Tibber_Diagramm\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;3_EVU_Tibber_Diagramm&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
  my (@out) = (&amp;quot;&amp;quot;) x 2;;\&lt;br /&gt;
  my $timestamp;;\&lt;br /&gt;
\&lt;br /&gt;
  for (my $j=0;;$j&amp;lt;=1;;$j++){\&lt;br /&gt;
\&lt;br /&gt;
    if (ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_00_startsAt&amp;quot;,$j),&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot;) {       ## Der nächste Tag ist noch nicht da\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
        Log 3, &amp;quot;$SELF 3   Diagramm   : Tibber Daten für fc&amp;quot;.$j.&amp;quot; sind noch nicht da&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
\&lt;br /&gt;
      $timestamp = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time+86400));;    ## Setze das Datum auf morgen\&lt;br /&gt;
      for (my $k=0;;$k&amp;lt;=24;;$k++) {\&lt;br /&gt;
        $out[$j] .= sprintf(&amp;quot;%s_%02d:00:00 0.0\n&amp;quot;, $timestamp, $k);;      ## Die Daten mit 0 ergänzen\&lt;br /&gt;
      }\&lt;br /&gt;
      $j = 2;;                                                            ## Aus der Schleife springen\&lt;br /&gt;
\&lt;br /&gt;
    } else {\&lt;br /&gt;
\&lt;br /&gt;
      for (my $i=0;;$i&amp;lt;=23;;$i++){\&lt;br /&gt;
        $timestamp = ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_startsAt&amp;quot;,$j,$i),&amp;quot;&amp;quot;);;\&lt;br /&gt;
        $timestamp =~ s/ /_/g;;\&lt;br /&gt;
        $out[$j] .=$timestamp.&amp;quot; &amp;quot;.::round(ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,sprintf(&amp;quot;fc%d_%02d_total&amp;quot;,$j, $i),0)*100,1).&amp;quot;\n&amp;quot;;;\&lt;br /&gt;
      } # End $i\&lt;br /&gt;
\&lt;br /&gt;
    } # End if\&lt;br /&gt;
  } # End $j\&lt;br /&gt;
  \&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF 3   Diagramm   : Werte für das Diagramm&amp;quot;;;\&lt;br /&gt;
      print($out[0]);;\&lt;br /&gt;
      print($out[1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\&lt;br /&gt;
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_price&amp;quot;,&amp;quot;bar1day&amp;quot;,0,$out[0]);;\&lt;br /&gt;
  ::DOIF_modify_card_data(&amp;quot;EVU_Tibber&amp;quot;,&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;current_level&amp;quot;,&amp;quot;bar1day&amp;quot;,-86400,$out[1]);;\&lt;br /&gt;
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\&lt;br /&gt;
  ::CommandGet(undef, &amp;quot;EVU_Tibber_connect 01_priceInfo&amp;quot;);;                ## Kosten der letzen drei Stunden\&lt;br /&gt;
##  fhem(&amp;quot;get EVU_Tibber_connect 01_priceInfo&amp;quot;);;                           ## Kosten der letzen drei Stunden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr EVU_Tibber DbLogExclude .*&lt;br /&gt;
attr EVU_Tibber comment Version 2023.12.06 13:00 \&lt;br /&gt;
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.&lt;br /&gt;
attr EVU_Tibber disable 0&lt;br /&gt;
attr EVU_Tibber group PV Steuerung EVU&lt;br /&gt;
attr EVU_Tibber icon stromzaehler_icon&lt;br /&gt;
attr EVU_Tibber room Strom-&amp;gt;Boerse&lt;br /&gt;
attr EVU_Tibber sortby 315&lt;br /&gt;
attr EVU_Tibber uiState {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..6}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{1..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..6}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm&amp;quot;) |&amp;quot;LiveMessurement &amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:ui_command_2],&amp;quot;uzsuDropDown,---,connect,disconnect&amp;quot;)|&amp;quot;&amp;quot;|[EVU_Tibber_connect:ws_cmd]\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strompreis&amp;lt;br&amp;gt;&amp;quot;.card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,&amp;quot;fc0  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;).card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,&amp;quot;fc1  &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;),undef,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,220&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;nächste 3h&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Price(1).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(2).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Price(3)|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Statistik fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_min&amp;quot;,0).&amp;quot; min&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_avg&amp;quot;,0).&amp;quot; avg&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_med&amp;quot;,0).&amp;quot; med&amp;lt;br&amp;gt;&amp;quot;.::ReadingsVal(Device(),&amp;quot;fc_max&amp;quot;,0).&amp;quot; max&amp;quot;|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc0&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;Basis &amp;quot;.widget([EVU_Tibber_connect:compensation_grid],&amp;quot;selectnumbers,0,0.1,12,1,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_0&amp;quot;)|\&lt;br /&gt;
&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Trigger fc1&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.Format(&amp;quot;trigger_1&amp;quot;)&lt;br /&gt;
attr EVU_Tibber uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
   $TD{0..18}{0} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-left-style:solid;;border-left-width:2px;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{1..5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..18}{6} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Device {\&lt;br /&gt;
    return &amp;quot;$SELF&amp;quot;.&amp;quot;_connect&amp;quot;;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
sub Cost {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $currency = (::ReadingsVal(Device(),&amp;quot;current_currency&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;EUR&amp;quot;)? &amp;quot; €&amp;quot; : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  return ::ReadingsVal(Device(),&amp;quot;total_cost_&amp;quot;.$i,0).$currency;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
sub Price {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
  my $j;;\&lt;br /&gt;
  my $value;;\&lt;br /&gt;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i == 0) {\&lt;br /&gt;
    $value = ::ReadingsVal(Device(),&amp;quot;current_price&amp;quot;,0);;\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc0_trigger&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot; ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value .= &amp;quot; ct/kWh&amp;quot;;;\&lt;br /&gt;
  } else {\&lt;br /&gt;
    $j       = $i+$hour;;\&lt;br /&gt;
    if ($j &amp;lt; 24) {\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc0_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    } else {\&lt;br /&gt;
      $j = $j - 24;;\&lt;br /&gt;
      $value = ::round(::ReadingsVal(Device(),&amp;quot;fc1_&amp;quot;.sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot;_total&amp;quot;,0)*100,1);;\&lt;br /&gt;
    }\&lt;br /&gt;
    $value = ( ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;0&amp;quot;) &amp;gt; $value ) ?\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
         &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;&amp;quot;.$value.&amp;quot;&amp;lt;/span&amp;gt;&amp;quot; ;;\&lt;br /&gt;
    $value = sprintf(&amp;quot;%02d&amp;quot;,$j).&amp;quot; :  &amp;quot;.$value ;;\&lt;br /&gt;
  }\&lt;br /&gt;
  return  $value;;\&lt;br /&gt;
 }\&lt;br /&gt;
\&lt;br /&gt;
sub Format {\&lt;br /&gt;
  my($i)=@_;;\&lt;br /&gt;
\&lt;br /&gt;
  my $MonthBefore   = &amp;quot;LogDBRep_Statistic_previous_Month&amp;quot;;;\&lt;br /&gt;
  my $MonthPrevious = ::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $MonthPrevious = ($MonthPrevious ne &amp;quot;null&amp;quot;) ?    POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  my $YearBefore   = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
  my $YearPrevious = ::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
       $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,Device().&amp;quot;_nodes_consumption_year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  if ($i eq &amp;quot;day&amp;quot;) {\&lt;br /&gt;
      return sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_day&amp;quot;,0));;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;month&amp;quot;) {\&lt;br /&gt;
      my $evu_em = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_month&amp;quot;,0));;\&lt;br /&gt;
      $evu_em .= ($MonthPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$MonthBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_em;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;year&amp;quot;) {\&lt;br /&gt;
      my $evu_ey = sprintf(&amp;quot;%04d&amp;quot;,::ReadingsVal(Device(),&amp;quot;nodes_consumption_year&amp;quot;,0));;\&lt;br /&gt;
      $evu_ey .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ::ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;EVU_Tibber_Pulse_nodes_consumption_month&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
      return $evu_ey;;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_0&amp;quot;) {\&lt;br /&gt;
      return ((::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Heute kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
            &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc0_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc0_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                 ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
    } elsif ($i eq &amp;quot;trigger_1&amp;quot;) {\&lt;br /&gt;
      if (::ReadingsVal(Device(),&amp;quot;fc1_00_startsAt&amp;quot;,&amp;quot;null&amp;quot;) ne &amp;quot;null&amp;quot;) {\&lt;br /&gt;
        return ((::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;null&amp;quot;) eq &amp;quot;null&amp;quot; ) ?\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Morgen kein Trigger &amp;lt;br&amp;gt;mehr unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; :\&lt;br /&gt;
              &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Morgen ein Trigger von&amp;lt;br&amp;gt;&amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc1_trigger_start&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot; bis &amp;quot;.::ReadingsVal(Device(),&amp;quot;fc1_trigger_stop&amp;quot;,&amp;quot;00:00&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;unter &amp;quot;.\&lt;br /&gt;
                   ::ReadingsVal(Device(),&amp;quot;fc_trigger_price&amp;quot;,&amp;quot;null&amp;quot;).&amp;quot; ct&amp;lt;/span&amp;gt;&amp;quot; );;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        return &amp;quot;Morgen noch kein Trigger vorhanden&amp;quot;;;\&lt;br /&gt;
      }\&lt;br /&gt;
    }\&lt;br /&gt;
  return &amp;quot;null&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Statistiken &amp;quot;.::ReadingsVal(Device(),&amp;quot;current_date&amp;quot;,0).&amp;quot; in kWh&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;aktuell&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;heute&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Monat&amp;lt;/span&amp;gt;&amp;quot;|&amp;quot;&amp;lt;span style=font-weight:bold&amp;gt;Jahr&amp;lt;/span&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;lt;dd&amp;gt;Preis / Kosten&amp;lt;/dd&amp;gt;&amp;quot;|Price(0)|Cost(&amp;quot;day&amp;quot;)|Cost(&amp;quot;month&amp;quot;)|Cost(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man das liveMessurment von Tibber verwendet\&lt;br /&gt;
&amp;quot;Bezug vom Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_power]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_power&amp;quot;,0) : 0))|\&lt;br /&gt;
Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Einspeisung ins Netz&amp;quot;|\&lt;br /&gt;
sprintf(&amp;quot;%04d W&amp;quot;,([EVU_Tibber_connect:payload_data_liveMeasurement_powerProduction]  &amp;gt;= 0 ? ::ReadingsVal(&amp;quot;EVU_Tibber_connect&amp;quot;,&amp;quot;payload_data_liveMeasurement_powerProduction&amp;quot;,0) : 0))|\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
## Wenn man einen eigenes SmartMeter verwendet\&lt;br /&gt;
## &amp;quot;Bezug vom Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;gt;= 0 ? ::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0) : 0) )|Format(&amp;quot;day&amp;quot;)|Format(&amp;quot;month&amp;quot;)|Format(&amp;quot;year&amp;quot;)\&lt;br /&gt;
## &amp;quot;Einspeisung ins Netz&amp;quot;|sprintf(&amp;quot;%04d W&amp;quot;,([WR_0_KSEM:M_AC_Power] &amp;lt;= 0 ? abs(::round(::ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;M_AC_Power&amp;quot;,0),0)) :  0) )|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;&lt;br /&gt;
attr EVU_Tibber verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate EVU_Tibber 2024-01-23 10:03:00 ui_command_1 ---&lt;br /&gt;
setstate EVU_Tibber 2024-01-20 17:40:53 ui_command_2 ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39002</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39002"/>
		<updated>2024-01-22T14:57:14Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Device Übersicht mit Hilfen zur Orientierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* readingsGroup&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
* SVG&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ cat docker-compose.yml&lt;br /&gt;
# This is an exmaple Docker Compose file to start your own Docker Stack&lt;br /&gt;
&lt;br /&gt;
version: &#039;3.3&#039;&lt;br /&gt;
&lt;br /&gt;
volumes:&lt;br /&gt;
  portainer_data:&lt;br /&gt;
&lt;br /&gt;
services:&lt;br /&gt;
&lt;br /&gt;
  fhem:&lt;br /&gt;
    image: fhem/fhem:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
#    network_mode: host&lt;br /&gt;
#    privileged: true&lt;br /&gt;
#    devices:&lt;br /&gt;
#      - &amp;quot;/dev/ttyACM0:/dev/ttyACM0&amp;quot;&lt;br /&gt;
    volumes:&lt;br /&gt;
      - &amp;quot;./fhem/:/opt/fhem/&amp;quot;&lt;br /&gt;
#      - &amp;quot;./fhem/contrib/configDB/configDB.conf:/opt/fhem/configDB.conf&amp;quot;&lt;br /&gt;
    environment:&lt;br /&gt;
## Hier können gewünschte Zusatzpakete in den Container nachgeladen werden.&lt;br /&gt;
#      PIP_PKGS: &amp;quot;vallox_websocket_api fhem beautifulsoup4&amp;quot;&lt;br /&gt;
#      CPAN_PKGS: &amp;quot;Crypt::OpenSSL::AES XML::Bare XML::Bare Protocol::WebSocket::Handshake::Server Crypt::Rijndael Crypt::Random --verbose&amp;quot;&lt;br /&gt;
###########&lt;br /&gt;
      FHEM_UID: 6061&lt;br /&gt;
      FHEM_GID: 6061&lt;br /&gt;
      TIMEOUT: 10&lt;br /&gt;
      RESTART: 1&lt;br /&gt;
      TELNETPORT: 7072&lt;br /&gt;
      TZ: Europe/Berlin&lt;br /&gt;
#      CONFIGTYPE: configDB&lt;br /&gt;
    depends_on:&lt;br /&gt;
      - &amp;quot;mysql&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  mysql:&lt;br /&gt;
    image: mysql/mysql-server&lt;br /&gt;
    restart: always&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &#039;3306:3306&#039;&lt;br /&gt;
      - &#039;33060:33060&#039;&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/fhem-init.sql&lt;br /&gt;
      - ./mysql/data:/var/lib/mysql&lt;br /&gt;
      - ./mysql/log:/var/log&lt;br /&gt;
      - ./mysql/mycustom.cnf:/etc/mysql/conf.d/custom.cnf&lt;br /&gt;
    environment:&lt;br /&gt;
#      TZ: Europe/Berlin&lt;br /&gt;
      MYSQL_ROOT_PASSWORD: &amp;lt;root Passwort&amp;gt;&lt;br /&gt;
#      MYSQL_ROOT_HOST: 172.*.*.*&lt;br /&gt;
      MYSQL_DATABASE: fhem&lt;br /&gt;
      MYSQL_USER: fhemuser&lt;br /&gt;
      MYSQL_PASSWORD: &amp;lt;fhemuser Passwort&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  portainer:&lt;br /&gt;
    image: portainer/portainer:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
    ports:&lt;br /&gt;
        - &#039;9000:9000&#039;&lt;br /&gt;
    environment:&lt;br /&gt;
      - REGISTRY_HTTP_TLS_CERTIFICATE=/certs/portainer.crt&lt;br /&gt;
      - REGISTRY_HTTP_TLS_KEY=/certs/portainer.key&lt;br /&gt;
    volumes:&lt;br /&gt;
      - /var/run/docker.sock:/var/run/docker.sock&lt;br /&gt;
      - portainer_data:/data&lt;br /&gt;
      - ./certs/portainer.key:/certs/portainer.key&lt;br /&gt;
      - ./certs/portainer.crt:/certs/portainer.crt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1_config======&lt;br /&gt;
Dieses Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehreren Wechselrichtern kann man die Module mit ihren Ausrichtungen für die Leistungsprognose alle in die erste Konfiguration legen. So ergibt sich später eine gemeinsame Prognose für die gesamte PV-Anlage. Wenn man dies auf einzelne Konfigurationsdummys aufteilt, kann man für jeden Wechselrichter eine eigene Prognose erstellen. Eine Einzel- und Gesamtprognose wäre ebenfalls denkbar. Fragen dazu bitte im Forum stellen.&lt;br /&gt;
&lt;br /&gt;
In der readingList und setList können die Namen der Ausrichtung frei gewählt werden.&lt;br /&gt;
&lt;br /&gt;
Die default Einstellungen wurden bereits über Sommer und Winter getestet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_config dummy&lt;br /&gt;
attr WR_1_config DbLogExclude .*&lt;br /&gt;
attr WR_1_config alias WR_1_config&lt;br /&gt;
attr WR_1_config comment Version 2021.04.07 12:00\&lt;br /&gt;
Passworte für die Abfrage des WR_1_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr WR_1_config event-on-change-reading .*&lt;br /&gt;
attr WR_1_config group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_config icon solar_icon&lt;br /&gt;
attr WR_1_config readingList IP-WR_1 IP-WR_1_Speicher_1 IP-WR_1_KSEM IP-FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name  module_4_name module_5_name module_1_direction module_2_direction module_3_direction module_4_direction module_5_direction module_1_count module_2_count module_3_count module_4_count module_5_count module_1_power module_2_power module_3_power module_4_power module_5_power module_1_plain module_2_plain module_3_plain module_4_plain module_5_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor forecast_factor_autocorrection Forecast_Station&lt;br /&gt;
attr WR_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_config setList IP-WR_1 IP-WR_1_Speicher_1 IP-WR_1_KSEM IP-FHEM module_1_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort module_2_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort module_3_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_4_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_5_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_1_direction module_2_direction module_3_direction module_4_direction module_5_direction module_1_count module_2_count module_3_count module_4_count module_5_count module_1_power module_2_power module_3_power module_4_power module_5_power module_1_plain module_2_plain module_3_plain module_4_plain module_5_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor forecast_factor_autocorrection Forecast_Station&lt;br /&gt;
attr WR_1_config sortby 113&lt;br /&gt;
attr WR_1_config verbose 0&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_config 2020-09-11 07:36:39 Forecast_Station P0178&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:39:26 IP-FHEM 192.168.178.xxx&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:39:44 IP-WR_1 192.168.178.yyy&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:43:27 IP-WR_1_KSEM 192.168.178.zzz&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:44:46 IP-WR_1_Speicher_1 192.168.178.xyz&lt;br /&gt;
setstate WR_1_config 2020-09-22 10:03:21 forecast_cloudk 45&lt;br /&gt;
setstate WR_1_config 2020-09-22 10:12:17 forecast_cloudk_base 0&lt;br /&gt;
setstate WR_1_config 2020-12-07 15:49:18 forecast_factor 1&lt;br /&gt;
setstate WR_1_config 2021-03-31 11:45:19 forecast_factor_autocorrection 0&lt;br /&gt;
setstate WR_1_config 2020-09-02 18:40:29 forecast_raink 20&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:52:40 forecast_raink_base 0&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:46:57 forecast_tempk 39&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:50:06 forecast_tempk_base 25&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:31:19 module_1_count 20&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:27:38 module_1_direction -90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:33:27 module_1_name WR_1_Ost&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:29:42 module_1_plain 40&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:31:09 module_1_power 310&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:10 module_2_count 16&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:13 module_2_direction 90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:33:45 module_2_name WR_1_West&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:34:14 module_2_plain 40&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:23:00 module_2_power 310&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:40 module_3_count 13&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:26 module_3_direction 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:34:09 module_3_name WR_2_Sued&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:35:08 module_3_plain 40&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:55 module_3_power 340&lt;br /&gt;
setstate WR_1_config 2021-03-29 12:20:49 module_4_count 11&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:37 module_4_direction 90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:34:27 module_4_name WR_2_West&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:34:14 module_4_plain 40&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:23:00 module_4_power 340&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:41:15 module_5_count 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:53:22 module_5_direction 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:43:38 module_5_name frei&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:50:46 module_5_plain 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:50:39 module_5_power 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1 ModbusAttr 71 60 &amp;lt;IP-Adresse&amp;gt;:1502 TCP&lt;br /&gt;
attr WR_1 DbLogExclude .*&lt;br /&gt;
attr WR_1 DbLogInclude Act_state_of_charge,Actual_Battery_charge_-minus_or_discharge_-plus_P,Actual_Battery_charge_usable_P,Battery_Total.*,Battery_charge.*,Battery_gross.*,Battery_temperature,Battery_MaxChargePowerLimitAbs,Battery_.*SOC,P_DC1,P_DC2,Total_.*,Solar_Calculation,Solar_Calculation_fc0_4h,Solar_Calculation_fc0_day,Solar_Calculation_fc0_rest,Solar_Correction.*,Solar_Cloud,Solar_East_Covered,Solar_Rain,Solar_SolarRadiation,Solar_Temp,Solar_WR_.*,Solar_middayhigh.*,SW_.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_1 alias WR_1&lt;br /&gt;
attr WR_1 alignTime 00:00&lt;br /&gt;
attr WR_1 comment Version 2022.12.30 10:00\&lt;br /&gt;
Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr WR_1 dev-h-combine 8&lt;br /&gt;
attr WR_1 dev-h-defFormat %.2f&lt;br /&gt;
attr WR_1 dev-h-defLen 2&lt;br /&gt;
attr WR_1 dev-h-defPoll 1&lt;br /&gt;
attr WR_1 dev-h-defRevRegs 1&lt;br /&gt;
attr WR_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr WR_1 dev-type-STR-format %s&lt;br /&gt;
attr WR_1 dev-type-STR-len 8&lt;br /&gt;
attr WR_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr WR_1 dev-type-STR-unpack a*&lt;br /&gt;
attr WR_1 disable 0&lt;br /&gt;
attr WR_1 event-on-change-reading Act_state_of_charge,Actual_Battery_charge_-minus_or_discharge_-plus_I,Actual_Battery_charge_-minus_or_discharge_-plus_P,Actual_Battery_charge_usable_P,Battery_Total.*,Battery_charge.*,Battery_gross.*,Battery_temperature,Battery_MaxChargePowerLimitAbs,Battery_.*SOC,Home_own_consumption.*,P_DC1,P_DC2,Solar_.*,Total_.*,SW_.*,.*_yield,Inverter_state.*,Inverter_Generation_P_Actual.*,Solar_Calculation_fc.*_day&lt;br /&gt;
attr WR_1 event-on-update-reading P_limit_from_EVU.*&lt;br /&gt;
attr WR_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1 icon sani_solar&lt;br /&gt;
attr WR_1 obj-h100-reading Total_DC_P&lt;br /&gt;
attr WR_1 obj-h1024-len 1&lt;br /&gt;
attr WR_1 obj-h1024-reading Battery_Charge_AC_P_Setpoint&lt;br /&gt;
attr WR_1 obj-h1024-set 1&lt;br /&gt;
attr WR_1 obj-h1024-unpack n&lt;br /&gt;
attr WR_1 obj-h1025-len 1&lt;br /&gt;
attr WR_1 obj-h1025-reading Battery_P_ScaleFactor&lt;br /&gt;
attr WR_1 obj-h1025-unpack n&lt;br /&gt;
attr WR_1 obj-h1026-reading Battery_Charge_AC_P_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1026-set 1&lt;br /&gt;
attr WR_1 obj-h1028-reading Battery_Charge_DC_I_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1028-set 1&lt;br /&gt;
attr WR_1 obj-h1030-reading Battery_Charge_AC_P_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1030-set 1&lt;br /&gt;
attr WR_1 obj-h1032-reading Battery_Charge_DC_I_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1032-set 1&lt;br /&gt;
attr WR_1 obj-h1034-reading Battery_Charge_DC_P_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1034-set 1&lt;br /&gt;
attr WR_1 obj-h1036-reading Battery_Charge_DC_P_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1036-set 1&lt;br /&gt;
attr WR_1 obj-h1038-reading Battery_MaxChargePowerLimitAbs&lt;br /&gt;
attr WR_1 obj-h1038-set 1&lt;br /&gt;
attr WR_1 obj-h104-format %s&lt;br /&gt;
attr WR_1 obj-h104-map 0:Normal,8:Ruhe1,16:Ruhe2,32:Ausgleichsladung,64:Tiefentladeschutz,256:externe Batteriesteuerung&lt;br /&gt;
attr WR_1 obj-h104-reading State_of_EM&lt;br /&gt;
attr WR_1 obj-h104-revRegs 0&lt;br /&gt;
attr WR_1 obj-h104-unpack N&lt;br /&gt;
attr WR_1 obj-h1040-reading Battery_MaxDischargePowerLimitAbs&lt;br /&gt;
attr WR_1 obj-h1040-set 1&lt;br /&gt;
attr WR_1 obj-h1042-reading Battery_MinSOC&lt;br /&gt;
attr WR_1 obj-h1042-set 1&lt;br /&gt;
attr WR_1 obj-h1044-reading Battery_MaxSOC&lt;br /&gt;
attr WR_1 obj-h1044-set 1&lt;br /&gt;
attr WR_1 obj-h1046-reading Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
attr WR_1 obj-h1048-reading Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
attr WR_1 obj-h1050-reading Battery_Total_AC_ChargeEnergy_ACsideToBattery&lt;br /&gt;
attr WR_1 obj-h1052-reading Battery_Total_AC_DischargeEnergy_BatteryToGrid&lt;br /&gt;
attr WR_1 obj-h1054-reading Battery_Total_AC_ChargeEnergy_gridToBattery&lt;br /&gt;
attr WR_1 obj-h1056-reading Total_DC_PV_Energy_sumOfAllPVInputs&lt;br /&gt;
attr WR_1 obj-h1058-reading Total_DC_Energy_From_PV1&lt;br /&gt;
attr WR_1 obj-h106-reading Home_own_consumption_from_Battery&lt;br /&gt;
attr WR_1 obj-h1060-reading Total_DC_Energy_From_PV2&lt;br /&gt;
attr WR_1 obj-h1062-reading Total_DC_Energy_From_PV3&lt;br /&gt;
attr WR_1 obj-h1064-reading Total_AC_Energy_ACsideToGrid&lt;br /&gt;
attr WR_1 obj-h1066-reading Total_DC_P_sumOfAllPVInputs&lt;br /&gt;
attr WR_1 obj-h1068-reading Battery_work_capacity&lt;br /&gt;
attr WR_1 obj-h1070-reading Battery_serial_number&lt;br /&gt;
attr WR_1 obj-h1072-reading Battery_Reserved_1072&lt;br /&gt;
attr WR_1 obj-h1074-reading Battery_Reserved_1074&lt;br /&gt;
attr WR_1 obj-h1076-reading Battery_Maximum_ChargePLimit_read-outFromBattery&lt;br /&gt;
attr WR_1 obj-h1078-reading Battery_Maximum_DischargePLimit_read-outFromBattery&lt;br /&gt;
attr WR_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr WR_1 obj-h1080-reading Battery_management_mode&lt;br /&gt;
attr WR_1 obj-h1080-set 1&lt;br /&gt;
attr WR_1 obj-h1081-reading Battery_Reserved_1081&lt;br /&gt;
attr WR_1 obj-h1082-reading Installed_sensor_type&lt;br /&gt;
attr WR_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr WR_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr WR_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr WR_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr WR_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr WR_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr WR_1 obj-h122-reading P_limit_from_EVU&lt;br /&gt;
attr WR_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr WR_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr WR_1 obj-h14-type STR&lt;br /&gt;
attr WR_1 obj-h144-reading Worktime&lt;br /&gt;
attr WR_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr WR_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr WR_1 obj-h154-reading I_L1&lt;br /&gt;
attr WR_1 obj-h156-reading Active_P_L1&lt;br /&gt;
attr WR_1 obj-h158-reading U_L1&lt;br /&gt;
attr WR_1 obj-h160-reading I_L2&lt;br /&gt;
attr WR_1 obj-h162-reading Active_P_L2&lt;br /&gt;
attr WR_1 obj-h164-reading U_L2&lt;br /&gt;
attr WR_1 obj-h166-reading I_L3&lt;br /&gt;
attr WR_1 obj-h168-reading Active_P_L3&lt;br /&gt;
attr WR_1 obj-h170-reading U_L3&lt;br /&gt;
attr WR_1 obj-h172-reading Total_AC_Active_P&lt;br /&gt;
attr WR_1 obj-h174-reading Total_AC_Reactive_P&lt;br /&gt;
attr WR_1 obj-h178-reading Total_AC_Apparent_P&lt;br /&gt;
attr WR_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr WR_1 obj-h194-format %.0f&lt;br /&gt;
attr WR_1 obj-h194-reading Number_of_Battery_cycles&lt;br /&gt;
attr WR_1 obj-h200-reading Actual_Battery_charge_-minus_or_discharge_-plus_I&lt;br /&gt;
attr WR_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr WR_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr WR_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr WR_1 obj-h212-reading Battery_state&lt;br /&gt;
attr WR_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr WR_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr WR_1 obj-h218-reading Cos_phi_EM&lt;br /&gt;
attr WR_1 obj-h220-reading Frequency_EM&lt;br /&gt;
attr WR_1 obj-h222-reading I_L1_EM&lt;br /&gt;
attr WR_1 obj-h224-reading Active_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h226-reading Reactive_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h228-reading Apparent_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h230-reading U_L1_EM&lt;br /&gt;
attr WR_1 obj-h232-reading I_L2_EM&lt;br /&gt;
attr WR_1 obj-h234-reading Active_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h236-reading Reactive_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h238-reading Apparent_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h240-reading U_L2_EM&lt;br /&gt;
attr WR_1 obj-h242-reading I_L3_EM&lt;br /&gt;
attr WR_1 obj-h244-reading Active_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h246-reading Reactive_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h248-reading Apparent_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h250-reading U_L3_EM&lt;br /&gt;
attr WR_1 obj-h252-reading Total_Active_P_EM&lt;br /&gt;
attr WR_1 obj-h254-reading Total_Reactive_P_EM&lt;br /&gt;
attr WR_1 obj-h256-reading Total_Apparent_P_EM&lt;br /&gt;
attr WR_1 obj-h258-reading I_DC1&lt;br /&gt;
attr WR_1 obj-h260-reading P_DC1&lt;br /&gt;
attr WR_1 obj-h266-reading U_DC1&lt;br /&gt;
attr WR_1 obj-h268-reading I_DC2&lt;br /&gt;
attr WR_1 obj-h270-reading P_DC2&lt;br /&gt;
attr WR_1 obj-h276-reading U_DC2&lt;br /&gt;
attr WR_1 obj-h278-reading I_DC3&lt;br /&gt;
attr WR_1 obj-h280-reading P_DC3&lt;br /&gt;
attr WR_1 obj-h286-reading U_DC3&lt;br /&gt;
attr WR_1 obj-h320-reading Total_yield&lt;br /&gt;
attr WR_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr WR_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr WR_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr WR_1 obj-h38-reading Software-Version_Maincontroller_MC&lt;br /&gt;
attr WR_1 obj-h38-type STR&lt;br /&gt;
attr WR_1 obj-h384-len 16&lt;br /&gt;
attr WR_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr WR_1 obj-h384-type STR&lt;br /&gt;
attr WR_1 obj-h4-format %.0f&lt;br /&gt;
attr WR_1 obj-h4-len 1&lt;br /&gt;
attr WR_1 obj-h4-reading MODBUS_Unit-ID&lt;br /&gt;
attr WR_1 obj-h4-revRegs 1&lt;br /&gt;
attr WR_1 obj-h4-unpack N&lt;br /&gt;
attr WR_1 obj-h420-reading IP-address&lt;br /&gt;
attr WR_1 obj-h420-type STR&lt;br /&gt;
attr WR_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr WR_1 obj-h428-type STR&lt;br /&gt;
attr WR_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr WR_1 obj-h436-type STR&lt;br /&gt;
attr WR_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr WR_1 obj-h446-type STR&lt;br /&gt;
attr WR_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr WR_1 obj-h454-type STR&lt;br /&gt;
attr WR_1 obj-h46-reading Software-Version_IO-Controller_IOC&lt;br /&gt;
attr WR_1 obj-h46-type STR&lt;br /&gt;
attr WR_1 obj-h5-format %.0f&lt;br /&gt;
attr WR_1 obj-h5-len 1&lt;br /&gt;
attr WR_1 obj-h5-reading MODBUS_Byte_Order_Note&lt;br /&gt;
attr WR_1 obj-h5-revRegs 1&lt;br /&gt;
attr WR_1 obj-h5-unpack N&lt;br /&gt;
attr WR_1 obj-h512-format %s&lt;br /&gt;
attr WR_1 obj-h512-reading Battery_gross_capacity&lt;br /&gt;
attr WR_1 obj-h512-unpack N&lt;br /&gt;
attr WR_1 obj-h514-len 1&lt;br /&gt;
attr WR_1 obj-h514-reading Battery_Actual_SOC&lt;br /&gt;
attr WR_1 obj-h514-unpack n&lt;br /&gt;
attr WR_1 obj-h515-format %s&lt;br /&gt;
attr WR_1 obj-h515-reading Battery_Maincontroller_MC&lt;br /&gt;
attr WR_1 obj-h515-unpack N&lt;br /&gt;
attr WR_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr WR_1 obj-h517-type STR&lt;br /&gt;
attr WR_1 obj-h525-format %s&lt;br /&gt;
attr WR_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr WR_1 obj-h525-unpack N&lt;br /&gt;
attr WR_1 obj-h527-format %s&lt;br /&gt;
attr WR_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr WR_1 obj-h527-unpack N&lt;br /&gt;
attr WR_1 obj-h529-len 4&lt;br /&gt;
attr WR_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr WR_1 obj-h529-unpack N&lt;br /&gt;
attr WR_1 obj-h531-format %.0f&lt;br /&gt;
attr WR_1 obj-h531-reading Inverter_Max_P&lt;br /&gt;
attr WR_1 obj-h531-unpack N&lt;br /&gt;
attr WR_1 obj-h56-format %.0f&lt;br /&gt;
attr WR_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr WR_1 obj-h56-unpack N&lt;br /&gt;
attr WR_1 obj-h575-reading Inverter_Generation_P_Actual&lt;br /&gt;
attr WR_1 obj-h575-unpack N&lt;br /&gt;
attr WR_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr WR_1 obj-h577-unpack N&lt;br /&gt;
attr WR_1 obj-h578-reading Total_energy&lt;br /&gt;
attr WR_1 obj-h582-reading Actual_Battery_charge-discharge_P&lt;br /&gt;
attr WR_1 obj-h586-format %s&lt;br /&gt;
attr WR_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr WR_1 obj-h586-unpack N&lt;br /&gt;
attr WR_1 obj-h6-reading Inverter_Article_number&lt;br /&gt;
attr WR_1 obj-h6-type STR&lt;br /&gt;
attr WR_1 obj-h768-len 32&lt;br /&gt;
attr WR_1 obj-h768-reading Productname&lt;br /&gt;
attr WR_1 obj-h768-type STR&lt;br /&gt;
attr WR_1 obj-h800-len 32&lt;br /&gt;
attr WR_1 obj-h800-reading Power_class&lt;br /&gt;
attr WR_1 obj-h800-type STR&lt;br /&gt;
attr WR_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1 sortby 111&lt;br /&gt;
attr WR_1 stateFormat {\&lt;br /&gt;
 my $DUMMY  = &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $Power          = ReadingsVal($name,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_P&amp;quot;,0);;\&lt;br /&gt;
 my $StatusSpeicher = ($Power &amp;lt; -10) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot; : ($Power &amp;gt; 15)?  &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot;  : &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Standby&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
    $StatusSpeicher = $StatusSpeicher.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;State_of_EM&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
    $Power          = $Power.&amp;quot; W&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
 my $Battery_temperature                  = sprintf(&amp;quot;%.1f °C&amp;quot;,ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0));;\&lt;br /&gt;
    $Battery_temperature                  = ((ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;DigitalOutputs_ConfigurationFlags&amp;quot;,0) == 9) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Lüfter An &amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;quot; : &amp;quot;&amp;lt;br&amp;gt;&amp;quot;).$Battery_temperature;;\&lt;br /&gt;
\&lt;br /&gt;
 my $Actual_Battery_charge_usable_P       = sprintf(&amp;quot;%d Wh&amp;quot;,ReadingsVal($name,&amp;quot;Actual_Battery_charge_usable_P&amp;quot;,0));;\&lt;br /&gt;
								         \&lt;br /&gt;
 my $Act_state_of_charge                  = sprintf(&amp;quot;%d %%&amp;quot;,ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
 my $SW_Total_DC_P_sumOfAllPVInputs       = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
 my $SW_Total_PV_P_reserve                = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Total_PV_P_reserve&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
\&lt;br /&gt;
 my $SW_Home_own_consumption_from_PV      = sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0));;\&lt;br /&gt;
    $SW_Home_own_consumption_from_PV = ($SW_Home_own_consumption_from_PV &amp;gt;= 0) ? $SW_Home_own_consumption_from_PV.&amp;quot; W&amp;quot; : &amp;quot;0 W&amp;quot;;;\&lt;br /&gt;
 my $SW_Home_own_consumption_from_Battery = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0));;\&lt;br /&gt;
 my $SW_Home_own_consumption_from_grid    = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0));;\&lt;br /&gt;
 my $SW_Home_own_consumption              = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
 my $Total_Active_P_EM  = sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;Total_Active_P_EM&amp;quot;,0));;\&lt;br /&gt;
 my $StatusNetz         = ($Total_Active_P_EM &amp;lt; -10) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Einspeisen&amp;lt;/span&amp;gt;&amp;quot; : ($Total_Active_P_EM &amp;gt; 15)?  &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Netzbezug&amp;lt;/span&amp;gt;&amp;quot;  : &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Standby&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
    $Total_Active_P_EM  = $Total_Active_P_EM.&amp;quot; W&amp;quot;;;\&lt;br /&gt;
	 \&lt;br /&gt;
 my $SW_Yield_Daily   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Daily&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Monthly = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Monthly&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Yearly  = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Yearly&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Total   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Total&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
\&lt;br /&gt;
 my $Solar_Calculation_fc0_4h   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_4h&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $Solar_Calculation_fc0_day  = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_day&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $Solar_Calculation_fc0_rest = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_rest&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Wechselrichter / KSEM&amp;lt;dd&amp;gt;Max DC / PV Reserve / Netz Leistung&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Total_DC_P_sumOfAllPVInputs.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Total_PV_P_reserve.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$StatusNetz.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Total_Active_P_EM.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Leistung&amp;lt;dd&amp;gt;von PV / von Batterie / vom Netz / ins Haus&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_PV.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_Battery.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_grid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Ertrag&amp;lt;dd&amp;gt;Tag / Monat / Jahr / Total&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Daily.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Monthly.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Yearly.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Total.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Prognose&amp;lt;dd&amp;gt;Tag / 4 Stunden / Resttag&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_day.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_4h.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_rest.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Speicher&amp;lt;dd&amp;gt;Temperatur / nutzbare Ladung / Status / Leistung / akt. SOC&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Battery_temperature.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Actual_Battery_charge_usable_P.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$StatusSpeicher.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Power.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$Act_state_of_charge.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1 userReadings Total_PV_P_reserve:Total_DC_P.* {my $reserve = ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0);;;; ($reserve lt 0)? 0 : round($reserve,0)  },\&lt;br /&gt;
\&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_P:[Battery_voltage|Actual_Battery_charge_-minus_or_discharge_-plus_I].* {round((ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_I&amp;quot;,0)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_P_Max:[Total_DC_P_sumOfAllPVInputs|Actual_Battery_charge_-minus_or_discharge_-plus_P].* { my $Bat_P = ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_P&amp;quot;,0);;;; ($Bat_P gt 0)? round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0) + $Bat_P,0) : round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_Battery_charge_usable_P:[Act_state_of_charge|Battery_MinSOC].* {my $x = (ReadingsVal($NAME,&amp;quot;Battery_work_capacity&amp;quot;,0)*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,0)-ReadingsVal($NAME,&amp;quot;Battery_MinSOC&amp;quot;,0))/100);;;; ($x lt 0)? 0 : round($x,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Inverter_Generation_P_Actual:Inverter_Generation_P_Actual.* {round(ReadingsVal($NAME,&amp;quot;Inverter_Generation_P_Actual&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Inverter_Generation_P_Actual&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption:[Total_Active_P_EM:|Total_AC_Active_P:].* {round(ReadingsVal($NAME,&amp;quot;Total_Active_P_EM&amp;quot;,0)+ReadingsVal($NAME,&amp;quot;Total_AC_Active_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Active_P&amp;quot;,0),0)},\&lt;br /&gt;
SW_Total_AC_Active_P:Total_AC_Active_P:.*  {round(ReadingsVal($NAME,&amp;quot;Total_AC_Active_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Active_P&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P:Total_DC_P:.* {round(ReadingsVal($NAME,&amp;quot;Total_DC_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_P&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P_sumOfAllPVInputs:Total_DC_P_sumOfAllPVInputs.* {round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_PV_P_reserve:SW_Total_DC_P_sumOfAllPVInputs.* {my $reserve = ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0) * 0.90 - ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0);;;; ($reserve lt 0)? 0 : round($reserve,0)  },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P_Max:SW_Total_DC_P_sumOfAllPVInputs.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_I&amp;quot;,0)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,0));;;; ($Bat_out gt 0)? round(ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0) + $Bat_out,0) : round(ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Yield_Daily:Daily_yield.* { round(ReadingsVal($NAME,&amp;quot;Daily_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Daily_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Monthly:Monthly_yield.* { round(ReadingsVal($NAME,&amp;quot;Monthly_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Monthly_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Yearly:Yearly_yield.* { round(ReadingsVal($NAME,&amp;quot;Yearly_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Yearly_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Total:Total_yield.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_yield&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption_from_PV:[Total_Active_P_EM|SW_Home_own_consumption:|Home_own_consumption_from_grid|Home_own_consumption_from_Battery].* { (ReadingsVal($NAME,&amp;quot;Total_Active_P_EM&amp;quot;,0) ge 0) ? ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0) :  ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0);;;; },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption_from_Battery:[SW_Home_own_consumption_from_PV|Home_own_consumption_from_Battery].* { ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0) },\&lt;br /&gt;
SW_Home_own_consumption_from_grid:[SW_Home_own_consumption_from_PV|Home_own_consumption_from_grid].* { ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0) },\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Battery_Total_AC_ChargeEnergy_ACsideToBattery:Battery_Total_AC_ChargeEnergy_ACsideToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_ChargeEnergy_ACsideToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_AC_ChargeEnergy_gridToBattery:Battery_Total_AC_ChargeEnergy_gridToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_ChargeEnergy_gridToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_AC_DischargeEnergy_BatteryToGrid:Battery_Total_AC_DischargeEnergy_BatteryToGrid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_DischargeEnergy_BatteryToGrid&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_DC_ChargeEnergy_DCsideToBattery:Battery_Total_DC_ChargeEnergy_DCsideToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_DC_ChargeEnergy_DCsideToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_DC_DischargeEnergy_DCsideFromBattery:Battery_Total_DC_DischargeEnergy_DCsideFromBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_AC_Energy_ACsideToGrid:Total_AC_Energy_ACsideToGrid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_AC_Energy_ACsideToGrid&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Energy_ACsideToGrid&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_Energy_From_PV1:Total_DC_Energy_From_PV1.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV1&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV2:Total_DC_Energy_From_PV2.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV2&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV3:Total_DC_Energy_From_PV3.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV3&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV4:Total_DC_Energy_From_PV1.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV1&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV5:Total_DC_Energy_From_PV2.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV2&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV6:Total_DC_Energy_From_PV3.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV3&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_PV_Energy_sumOfAllPVInputs:Total_DC_PV_Energy_sumOfAllPVInputs.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_PV_Energy_sumOfAllPVInputs&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_PV_Energy_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_Battery:Total_home_consumption_Battery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_Battery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_Grid:Total_home_consumption_Grid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_Grid&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_PV:Total_home_consumption_PV.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_PV&amp;quot;,0),0) }&lt;br /&gt;
attr WR_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2 ModbusAttr 71 60 &amp;lt;Ip-Adresse&amp;gt;:1502 TCP&lt;br /&gt;
attr WR_2 DbLogExclude .*&lt;br /&gt;
attr WR_2 DbLogInclude P_DC1,P_DC2,P_DC3,Total_DC_P.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_2 alias WR_2&lt;br /&gt;
attr WR_2 alignTime 00:00&lt;br /&gt;
attr WR_2 comment Version 2021.06.02 14:00\&lt;br /&gt;
Kostal Plenticore Plus 7&lt;br /&gt;
attr WR_2 dev-h-combine 8&lt;br /&gt;
attr WR_2 dev-h-defFormat %.2f&lt;br /&gt;
attr WR_2 dev-h-defLen 2&lt;br /&gt;
attr WR_2 dev-h-defPoll 1&lt;br /&gt;
attr WR_2 dev-h-defRevRegs 1&lt;br /&gt;
attr WR_2 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr WR_2 dev-type-STR-format %s&lt;br /&gt;
attr WR_2 dev-type-STR-len 8&lt;br /&gt;
attr WR_2 dev-type-STR-revRegs 0&lt;br /&gt;
attr WR_2 dev-type-STR-unpack a*&lt;br /&gt;
attr WR_2 disable 0&lt;br /&gt;
attr WR_2 event-on-change-reading P_DC1,P_DC2,P_DC3,Total_DC_P.*,Total_DC_PV_Energy.*,Total_AC_Active_P.*,Inverter_state.*,Inverter_Generation_P_Actual.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_2 group PV Eigenverbrauch&lt;br /&gt;
attr WR_2 icon sani_solar&lt;br /&gt;
attr WR_2 obj-h100-reading Total_DC_P&lt;br /&gt;
attr WR_2 obj-h1058-reading Total_DC_Energy_From_PV1&lt;br /&gt;
attr WR_2 obj-h1060-reading Total_DC_Energy_From_PV2&lt;br /&gt;
attr WR_2 obj-h1062-reading Total_DC_Energy_From_PV3&lt;br /&gt;
attr WR_2 obj-h1064-reading Total_AC_Energy_ACsideToGrid&lt;br /&gt;
attr WR_2 obj-h1066-reading Total_DC_P_sumOfAllPVInputs&lt;br /&gt;
attr WR_2 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr WR_2 obj-h122-reading P_limit_from_EVU&lt;br /&gt;
attr WR_2 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr WR_2 obj-h14-type STR&lt;br /&gt;
attr WR_2 obj-h144-reading Worktime&lt;br /&gt;
attr WR_2 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr WR_2 obj-h152-reading Grid_frequency&lt;br /&gt;
attr WR_2 obj-h154-reading I_L1&lt;br /&gt;
attr WR_2 obj-h156-reading Active_P_L1&lt;br /&gt;
attr WR_2 obj-h158-reading U_L1&lt;br /&gt;
attr WR_2 obj-h160-reading I_L2&lt;br /&gt;
attr WR_2 obj-h162-reading Active_P_L2&lt;br /&gt;
attr WR_2 obj-h164-reading U_L2&lt;br /&gt;
attr WR_2 obj-h166-reading I_L3&lt;br /&gt;
attr WR_2 obj-h168-reading Active_P_L3&lt;br /&gt;
attr WR_2 obj-h170-reading U_L3&lt;br /&gt;
attr WR_2 obj-h172-reading Total_AC_Active_P&lt;br /&gt;
attr WR_2 obj-h174-reading Total_AC_Reactive_P&lt;br /&gt;
attr WR_2 obj-h178-reading Total_AC_Apparent_P&lt;br /&gt;
attr WR_2 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr WR_2 obj-h254-reading Total_Reactive_P_EM&lt;br /&gt;
attr WR_2 obj-h258-reading I_DC1&lt;br /&gt;
attr WR_2 obj-h260-reading P_DC1&lt;br /&gt;
attr WR_2 obj-h266-reading U_DC1&lt;br /&gt;
attr WR_2 obj-h268-reading I_DC2&lt;br /&gt;
attr WR_2 obj-h270-reading P_DC2&lt;br /&gt;
attr WR_2 obj-h276-reading U_DC2&lt;br /&gt;
attr WR_2 obj-h278-reading I_DC3&lt;br /&gt;
attr WR_2 obj-h280-reading P_DC3&lt;br /&gt;
attr WR_2 obj-h286-reading U_DC3&lt;br /&gt;
attr WR_2 obj-h320-reading Total_yield&lt;br /&gt;
attr WR_2 obj-h322-reading Daily_yield&lt;br /&gt;
attr WR_2 obj-h324-reading Yearly_yield&lt;br /&gt;
attr WR_2 obj-h326-reading Monthly_yield&lt;br /&gt;
attr WR_2 obj-h38-reading Software-Version_Maincontroller_MC&lt;br /&gt;
attr WR_2 obj-h38-type STR&lt;br /&gt;
attr WR_2 obj-h384-len 16&lt;br /&gt;
attr WR_2 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr WR_2 obj-h384-type STR&lt;br /&gt;
attr WR_2 obj-h420-reading IP-address&lt;br /&gt;
attr WR_2 obj-h420-type STR&lt;br /&gt;
attr WR_2 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr WR_2 obj-h428-type STR&lt;br /&gt;
attr WR_2 obj-h436-reading IP-gateway&lt;br /&gt;
attr WR_2 obj-h436-type STR&lt;br /&gt;
attr WR_2 obj-h446-reading IP-DNS1&lt;br /&gt;
attr WR_2 obj-h446-type STR&lt;br /&gt;
attr WR_2 obj-h454-reading IP-DNS2&lt;br /&gt;
attr WR_2 obj-h454-type STR&lt;br /&gt;
attr WR_2 obj-h46-reading Software-Version_IO-Controller_IOC&lt;br /&gt;
attr WR_2 obj-h46-type STR&lt;br /&gt;
attr WR_2 obj-h529-len 4&lt;br /&gt;
attr WR_2 obj-h529-reading Work_Capacity&lt;br /&gt;
attr WR_2 obj-h529-unpack N&lt;br /&gt;
attr WR_2 obj-h531-format %.0f&lt;br /&gt;
attr WR_2 obj-h531-reading Inverter_Max_P&lt;br /&gt;
attr WR_2 obj-h531-unpack N&lt;br /&gt;
attr WR_2 obj-h535-revRegs 0&lt;br /&gt;
attr WR_2 obj-h535-unpack n&lt;br /&gt;
attr WR_2 obj-h551-revRegs 0&lt;br /&gt;
attr WR_2 obj-h559-revRegs 0&lt;br /&gt;
attr WR_2 obj-h56-format %.0f&lt;br /&gt;
attr WR_2 obj-h56-reading Inverter_state&lt;br /&gt;
attr WR_2 obj-h56-unpack N&lt;br /&gt;
attr WR_2 obj-h575-reading Inverter_Generation_P_Actual&lt;br /&gt;
attr WR_2 obj-h575-unpack N&lt;br /&gt;
attr WR_2 obj-h577-len 2&lt;br /&gt;
attr WR_2 obj-h577-reading Generation_Energy&lt;br /&gt;
attr WR_2 obj-h577-unpack N&lt;br /&gt;
attr WR_2 obj-h578-reading Total_energy&lt;br /&gt;
attr WR_2 obj-h6-reading Inverter_Article_number&lt;br /&gt;
attr WR_2 obj-h6-type STR&lt;br /&gt;
attr WR_2 obj-h768-len 32&lt;br /&gt;
attr WR_2 obj-h768-reading Productname&lt;br /&gt;
attr WR_2 obj-h768-type STR&lt;br /&gt;
attr WR_2 obj-h800-len 32&lt;br /&gt;
attr WR_2 obj-h800-reading Power_class&lt;br /&gt;
attr WR_2 obj-h800-type STR&lt;br /&gt;
attr WR_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2 sortby 211&lt;br /&gt;
attr WR_2 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub plenticore_auth {&lt;br /&gt;
   my ($step, $user, $logdevice, $randomString, $nonce, $salt, $rounds, $transactionId, $token) = @_;&lt;br /&gt;
&lt;br /&gt;
   my $verbose     = AttrVal($logdevice,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
   my $PASSWD = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_&amp;quot;.$logdevice.&amp;quot;_&amp;quot;.$user);&lt;br /&gt;
&lt;br /&gt;
   if ($verbose &amp;gt;= 3) {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====Start plenticore_auth==============================&amp;quot;;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_step         : &amp;quot;.$step;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_user         : &amp;quot;.$user;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_device       : &amp;quot;.$logdevice;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_KeyValue read: PW_&amp;quot;.$logdevice.&amp;quot;_&amp;quot;.$user;&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   if($step eq &amp;quot;start&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     my @chars = (&#039;0&#039;..&#039;9&#039;, &#039;A&#039;..&#039;Z&#039;, &#039;a&#039;..&#039;z&#039;);&lt;br /&gt;
     my $len = 12;&lt;br /&gt;
     my $string;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     while($len--){ $string .= $chars[rand @chars] };&lt;br /&gt;
     $string = encode(&amp;quot;UTF-8&amp;quot;, $string);&lt;br /&gt;
     $string = decode(&amp;quot;UTF-8&amp;quot;, $string);&lt;br /&gt;
     my $u = encode_base64($string);&lt;br /&gt;
     $u =~ s/\n$//g;&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;nonce&amp;quot;: &amp;quot;&#039;.$u.&#039;&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;&#039;.$user.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_nonce        : &amp;quot;.$u;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
     &lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; auth_randomString64 &amp;quot;.$u) ;&lt;br /&gt;
 &lt;br /&gt;
    return $message;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
   ######### This code is identical for finish and session #################&lt;br /&gt;
   my $bitSalt = decode_base64($salt);&lt;br /&gt;
   my $r = derive( &#039;SHA-256&#039;, $PASSWD, $bitSalt, $rounds );&lt;br /&gt;
   my $ck = encode(&#039;UTF-8&#039;, &amp;quot;Client Key&amp;quot;);&lt;br /&gt;
   my $s = hmac_sha256($ck, $r);&lt;br /&gt;
   my $underscore = sha256($s);&lt;br /&gt;
   my $d = &amp;quot;n=&amp;quot;.$user.&amp;quot;,r=&amp;quot;.$randomString.&amp;quot;,r=&amp;quot;.$nonce.&amp;quot;,s=&amp;quot;.$salt.&amp;quot;,i=&amp;quot;.$rounds.&amp;quot;,c=biws,r=&amp;quot;.$nonce;&lt;br /&gt;
&lt;br /&gt;
   if ($verbose &amp;gt;= 3) {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_randomString : &amp;quot;.$randomString;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_nonce        : &amp;quot;.$nonce;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_salt         : &amp;quot;.$salt;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_rounds       : &amp;quot;.$rounds;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_transactionId: &amp;quot;.$transactionId;&lt;br /&gt;
   };&lt;br /&gt;
   &lt;br /&gt;
   if($step eq &amp;quot;finish&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
     my $sk = encode(&#039;UTF-8&#039;, &amp;quot;Server Key&amp;quot;);&lt;br /&gt;
     my $c = hmac_sha256($sk, $r);&lt;br /&gt;
     my $pd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $p = hmac_sha256($pd, $c);&lt;br /&gt;
     my $gd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $g = hmac_sha256($gd, $underscore);&lt;br /&gt;
     my $f = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $g1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $s1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $f1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $j = 0;&lt;br /&gt;
     for($j=0; $j&amp;lt;length($g); $j++) {&lt;br /&gt;
        $g1 = substr($g,$j,1);&lt;br /&gt;
        $s1 = substr($s,$j,1);&lt;br /&gt;
        $f1 = $s1 ^ $g1 ;&lt;br /&gt;
        $f = $f.$f1;&lt;br /&gt;
     }&lt;br /&gt;
     my $pe = encode_base64($f);&lt;br /&gt;
     $pe =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $proof = decode(&#039;UTF-8&#039;, $pe);&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;transactionId&amp;quot;: &amp;quot;&#039;.$transactionId.&#039;&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;&#039;.$proof.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_proof        : &amp;quot;.$proof;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     return $message;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
   if($step eq &amp;quot;session&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_token        : &amp;quot;.$token;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
     my $sk = encode(&#039;UTF-8&#039;, &amp;quot;Session Key&amp;quot;);&lt;br /&gt;
     my $dd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $protocol_key = hmac_sha256($sk, $dd, $s, $underscore);&lt;br /&gt;
&lt;br /&gt;
     my $t = &amp;quot;7244ba6f73c8cdc47b232e1311451939&amp;quot;;&lt;br /&gt;
     $t =~ s/([a-fA-F0-9][a-fA-F0-9])/chr(hex($1))/eg;&lt;br /&gt;
     my $e2 = Crypt::AuthEnc::GCM-&amp;gt;new(&amp;quot;AES&amp;quot;, $protocol_key, $t);&lt;br /&gt;
     my $tt = encode(&#039;UTF-8&#039;, $token);&lt;br /&gt;
     my $e2ct = $e2-&amp;gt;encrypt_add($tt);&lt;br /&gt;
     my $authtag = $e2-&amp;gt;encrypt_done();&lt;br /&gt;
&lt;br /&gt;
     $tt = encode_base64($t);&lt;br /&gt;
     $tt =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $iv = decode(&#039;UTF-8&#039;, $tt);&lt;br /&gt;
&lt;br /&gt;
     my $aa = encode_base64($authtag);&lt;br /&gt;
     $aa =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     $authtag = decode(&#039;UTF-8&#039;, $aa);&lt;br /&gt;
&lt;br /&gt;
     my $pp = encode_base64($e2ct);&lt;br /&gt;
     $pp =~ s/\n//g;                         # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $payload = decode(&#039;UTF-8&#039;, $pp);&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;transactionId&amp;quot;: &amp;quot;&#039;.$transactionId.&#039;&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;&#039;.$iv.&#039;&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;&#039;.$authtag.&#039;&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;&#039;.$payload.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_iv           : &amp;quot;.$iv;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_authtag      : &amp;quot;.$authtag;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_payload      : &amp;quot;.$payload;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
     &lt;br /&gt;
     return $message;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master ab v1.16&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_1_API userattr get25-1Name get25JSON get25Regex&lt;br /&gt;
attr WR_1_API DbLogExclude .*&lt;br /&gt;
attr WR_1_API DbLogInclude Statistic_Autarky.*,Statistic_Energy.*,Statistic_Own.*,Statistic_Total.*,Statistic_Yield.*,SW_.*&lt;br /&gt;
attr WR_1_API authRetries 1&lt;br /&gt;
attr WR_1_API comment Version 2022.03.29 09:00\&lt;br /&gt;
Passworte für die Abfrage des WR_1_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_1_API disable 0&lt;br /&gt;
attr WR_1_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_API enableControlSet 0&lt;br /&gt;
attr WR_1_API enableCookies 1&lt;br /&gt;
attr WR_1_API event-on-change-reading Battery_.*&lt;br /&gt;
attr WR_1_API event-on-update-reading auth_.*,Statistic_Autarky.*,Statistic_EnergyFeedIn.*,Statistic_EnergyHome.*,Statistic_EnergyPv[1|2].*,Statistic_.*Consumption.*,Statistic_Energy.*_Total,Statistic_Yield.*,SW_.*&lt;br /&gt;
attr WR_1_API get01Data %START%&lt;br /&gt;
attr WR_1_API get01Name 01_auth_start&lt;br /&gt;
attr WR_1_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_1_API get02Data %FINISH%&lt;br /&gt;
attr WR_1_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_1_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_1_API get03Data %SESSION%&lt;br /&gt;
attr WR_1_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_1_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_1_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_1_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_1_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_1_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_1_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_1_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get04JSON .&lt;br /&gt;
attr WR_1_API get04Name 04_auth_me&lt;br /&gt;
attr WR_1_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_1_API get05-1Name info_api_version&lt;br /&gt;
attr WR_1_API get05-2Name info_hostname&lt;br /&gt;
attr WR_1_API get05-3Name info_name&lt;br /&gt;
attr WR_1_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_1_API get05JSON .&lt;br /&gt;
attr WR_1_API get05Name 05_info_version&lt;br /&gt;
attr WR_1_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_1_API get20-10Format %.2f&lt;br /&gt;
attr WR_1_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_1_API get20-11Format %.2f&lt;br /&gt;
attr WR_1_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_1_API get20-12Format %.2f&lt;br /&gt;
attr WR_1_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_1_API get20-13Format %.2f&lt;br /&gt;
attr WR_1_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_1_API get20-14Format %.2f&lt;br /&gt;
attr WR_1_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_1_API get20-15Format %.2f&lt;br /&gt;
attr WR_1_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_1_API get20-16Format %.2f&lt;br /&gt;
attr WR_1_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_1_API get20-17Format %.2f&lt;br /&gt;
attr WR_1_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_1_API get20-18Format %.2f&lt;br /&gt;
attr WR_1_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_1_API get20-19Format %.2f&lt;br /&gt;
attr WR_1_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_1_API get20-1Format %.2f&lt;br /&gt;
attr WR_1_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_1_API get20-20Format %.2f&lt;br /&gt;
attr WR_1_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_1_API get20-21Format %.2f&lt;br /&gt;
attr WR_1_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_1_API get20-22Format %.2f&lt;br /&gt;
attr WR_1_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_1_API get20-23Format %.2f&lt;br /&gt;
attr WR_1_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_1_API get20-24Format %.2f&lt;br /&gt;
attr WR_1_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_1_API get20-25Format %.2f&lt;br /&gt;
attr WR_1_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_1_API get20-26Format %.2f&lt;br /&gt;
attr WR_1_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_1_API get20-27Format %.2f&lt;br /&gt;
attr WR_1_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_1_API get20-28Format %.2f&lt;br /&gt;
attr WR_1_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_1_API get20-29Format %.2f&lt;br /&gt;
attr WR_1_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_1_API get20-2Format %.2f&lt;br /&gt;
attr WR_1_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_1_API get20-30Format %.2f&lt;br /&gt;
attr WR_1_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_1_API get20-31Format %.2f&lt;br /&gt;
attr WR_1_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_1_API get20-32Format %.2f&lt;br /&gt;
attr WR_1_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_1_API get20-33Format %.2f&lt;br /&gt;
attr WR_1_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_1_API get20-34Format %.2f&lt;br /&gt;
attr WR_1_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_1_API get20-35Format %.2f&lt;br /&gt;
attr WR_1_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_1_API get20-36Format %.2f&lt;br /&gt;
attr WR_1_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_1_API get20-37Format %.2f&lt;br /&gt;
attr WR_1_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_1_API get20-38Format %.2f&lt;br /&gt;
attr WR_1_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_1_API get20-39Format %.2f&lt;br /&gt;
attr WR_1_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_1_API get20-3Format %.2f&lt;br /&gt;
attr WR_1_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_1_API get20-40Format %.2f&lt;br /&gt;
attr WR_1_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_1_API get20-41Format %.2f&lt;br /&gt;
attr WR_1_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_1_API get20-42Format %.2f&lt;br /&gt;
attr WR_1_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_1_API get20-43Format %.2f&lt;br /&gt;
attr WR_1_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_1_API get20-44Format %.2f&lt;br /&gt;
attr WR_1_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_1_API get20-45Format %.2f&lt;br /&gt;
attr WR_1_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_1_API get20-46Format %.2f&lt;br /&gt;
attr WR_1_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_1_API get20-47Format %.2f&lt;br /&gt;
attr WR_1_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_1_API get20-48Format %.2f&lt;br /&gt;
attr WR_1_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_1_API get20-49Format %.2f&lt;br /&gt;
attr WR_1_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_1_API get20-4Format %.2f&lt;br /&gt;
attr WR_1_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_1_API get20-50Format %.2f&lt;br /&gt;
attr WR_1_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_1_API get20-51Format %.2f&lt;br /&gt;
attr WR_1_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_1_API get20-52Format %.2f&lt;br /&gt;
attr WR_1_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_1_API get20-53Format %.2f&lt;br /&gt;
attr WR_1_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_1_API get20-54Format %.2f&lt;br /&gt;
attr WR_1_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_1_API get20-55Format %.2f&lt;br /&gt;
attr WR_1_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_1_API get20-56Format %.2f&lt;br /&gt;
attr WR_1_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_1_API get20-57Format %.2f&lt;br /&gt;
attr WR_1_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_1_API get20-58Format %.2f&lt;br /&gt;
attr WR_1_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_1_API get20-59Format %.2f&lt;br /&gt;
attr WR_1_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_1_API get20-5Format %.2f&lt;br /&gt;
attr WR_1_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_1_API get20-60Format %.2f&lt;br /&gt;
attr WR_1_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_1_API get20-61Format %.2f&lt;br /&gt;
attr WR_1_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_1_API get20-62Format %.2f&lt;br /&gt;
attr WR_1_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_1_API get20-63Format %.2f&lt;br /&gt;
attr WR_1_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_1_API get20-64Format %.2f&lt;br /&gt;
attr WR_1_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_1_API get20-65Format %.2f&lt;br /&gt;
attr WR_1_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_1_API get20-6Format %.2f&lt;br /&gt;
attr WR_1_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_1_API get20-7Format %.2f&lt;br /&gt;
attr WR_1_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_1_API get20-8Format %.2f&lt;br /&gt;
attr WR_1_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_1_API get20-9Format %.2f&lt;br /&gt;
attr WR_1_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_1_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_1_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_1_API get21-1Name Battery_Info_Cycles&lt;br /&gt;
attr WR_1_API get21-2Name Battery_Info_FullChargeCap_E&lt;br /&gt;
attr WR_1_API get21-3Name Battery_Info_SoC&lt;br /&gt;
attr WR_1_API get21-4Format %d&lt;br /&gt;
attr WR_1_API get21-4Name Battery_Info_WorkCapacity&lt;br /&gt;
attr WR_1_API get21Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get21Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get21JSON .._processdata_.._value&lt;br /&gt;
attr WR_1_API get21Name 21_Battery_Information&lt;br /&gt;
attr WR_1_API get21URL http://%IP-WR%/api/v1/processdata/devices:local:battery/Cycles,FullChargeCap_E,SoC,WorkCapacity&lt;br /&gt;
attr WR_1_API get22-1Name Battery_InternControl_DynamicSoc_Enable&lt;br /&gt;
attr WR_1_API get22-2Name Battery_Control&lt;br /&gt;
attr WR_1_API get22-3Format %d&lt;br /&gt;
attr WR_1_API get22-3Name Battery_InternControl_MinHomeConsumption&lt;br /&gt;
attr WR_1_API get22-4Name Battery_InternControl_MinSoc&lt;br /&gt;
attr WR_1_API get22-5Name Battery_InternControl_SmartBatteryControl_Enable&lt;br /&gt;
attr WR_1_API get22-6Name Battery_InternControl_Strategy&lt;br /&gt;
attr WR_1_API get22-7Name Battery_InternControl_Type&lt;br /&gt;
attr WR_1_API get22Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get22Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get22JSON .._value&lt;br /&gt;
attr WR_1_API get22Name 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API get22URL http://%IP-WR%/api/v1/settings/devices:local/Battery:ExternControl,Battery:Type,Battery:MinHomeComsumption,Battery:Strategy,Battery:MinSoc,Battery:SmartBatteryControl:Enable,Battery:DynamicSoc:Enable,Battery:Type&lt;br /&gt;
attr WR_1_API get23-10Format %d&lt;br /&gt;
attr WR_1_API get23-10Name Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
attr WR_1_API get23-11Format %d&lt;br /&gt;
attr WR_1_API get23-11Name Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
attr WR_1_API get23-12Format %d&lt;br /&gt;
attr WR_1_API get23-12Name Battery_ExternControl_MaxSocRel&lt;br /&gt;
attr WR_1_API get23-13Format %d&lt;br /&gt;
attr WR_1_API get23-13Name Battery_ExternControl_MinSocRel&lt;br /&gt;
attr WR_1_API get23-1Name Battery_ComMonitor_Enable&lt;br /&gt;
attr WR_1_API get23-2Format %d&lt;br /&gt;
attr WR_1_API get23-2Name Battery_ComMonitor_Time&lt;br /&gt;
attr WR_1_API get23-3Name Battery_Control&lt;br /&gt;
attr WR_1_API get23-4Format %.2f&lt;br /&gt;
attr WR_1_API get23-4Name Battery_ExternControl_AcPowerAbs&lt;br /&gt;
attr WR_1_API get23-5Format %.2f&lt;br /&gt;
attr WR_1_API get23-5Name Battery_ExternControl_AcPowerRel&lt;br /&gt;
attr WR_1_API get23-6Format %.2f&lt;br /&gt;
attr WR_1_API get23-6Name Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
attr WR_1_API get23-7Format %.2f&lt;br /&gt;
attr WR_1_API get23-7Name Battery_ExternControl_DcCurrentRel&lt;br /&gt;
attr WR_1_API get23-8Format %.2f&lt;br /&gt;
attr WR_1_API get23-8Name Battery_ExternControl_DcPowerAbs&lt;br /&gt;
attr WR_1_API get23-9Format %.2f&lt;br /&gt;
attr WR_1_API get23-9Name Battery_ExternControl_DcPowerRel&lt;br /&gt;
attr WR_1_API get23Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get23Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get23JSON .._value&lt;br /&gt;
attr WR_1_API get23Name 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API get23URL http://%IP-WR%/api/v1/settings/devices:local/Battery:ComMonitor:Enable,Battery:ComMonitor:Time,Battery:ExternControl,Battery:ExternControl:AcPowerAbs,Battery:ExternControl:AcPowerRel,Battery:ExternControl:DcCurrentAbs,Battery:ExternControl:DcCurrentRel,Battery:ExternControl:DcPowerAbs,Battery:ExternControl:DcPowerRel,Battery:ExternControl:MaxChargePowerAbs,Battery:ExternControl:MaxDischargePowerAbs,Battery:ExternControl:MaxSocRel,Battery:ExternControl:MinSocRel&lt;br /&gt;
attr WR_1_API get24-1Name Battery_TimeControl_1&lt;br /&gt;
attr WR_1_API get24-2Name Battery_TimeControl_2&lt;br /&gt;
attr WR_1_API get24-3Name Battery_TimeControl_3&lt;br /&gt;
attr WR_1_API get24-4Name Battery_TimeControl_4&lt;br /&gt;
attr WR_1_API get24-5Name Battery_TimeControl_5&lt;br /&gt;
attr WR_1_API get24-6Name Battery_TimeControl_6&lt;br /&gt;
attr WR_1_API get24-7Name Battery_TimeControl_7&lt;br /&gt;
attr WR_1_API get24-8Name Battery_TimeControl&lt;br /&gt;
attr WR_1_API get24Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get24Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get24JSON .._value&lt;br /&gt;
attr WR_1_API get24Name 24_Battery_TimeControl&lt;br /&gt;
attr WR_1_API get24URL http://%IP-WR%/api/v1/settings/devices:local/Battery:TimeControl:Enable,Battery:TimeControl:ConfMon,Battery:TimeControl:ConfTue,Battery:TimeControl:ConfWed,Battery:TimeControl:ConfThu,Battery:TimeControl:ConfFri,Battery:TimeControl:ConfSat,Battery:TimeControl:ConfSun&lt;br /&gt;
attr WR_1_API get25Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get25Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get25Name 25_Battery_EM_State&lt;br /&gt;
attr WR_1_API get25URL http://%IP-WR%/api/v1/processdata/devices:local/EM_State&lt;br /&gt;
attr WR_1_API get40-1Name EnergyMgmt_AcStorage&lt;br /&gt;
attr WR_1_API get40-2Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get40JSON .._value&lt;br /&gt;
attr WR_1_API get40Name 40_Generator_und_EnergieMgmt&lt;br /&gt;
attr WR_1_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable,EnergyMgmt:AcStorage&lt;br /&gt;
attr WR_1_API get41-1Name DigitalOutputs_ConfigurationFlags&lt;br /&gt;
attr WR_1_API get41-2Name DigitalOutputs_DelayTime&lt;br /&gt;
attr WR_1_API get41-3Name DigitalOutputs_PowerMode_OffPowerThreshold&lt;br /&gt;
attr WR_1_API get41-4Name DigitalOutputs_PowerMode_OnPowerThreshold&lt;br /&gt;
attr WR_1_API get41-5Name DigitalOutputs_SwitchOffDuration&lt;br /&gt;
attr WR_1_API get41-6Name DigitalOutputs_TimeMode_MaxNoOfSwitchingCyclesPerDay&lt;br /&gt;
attr WR_1_API get41-7Name DigitalOutputs_TimeMode_PowerThreshold&lt;br /&gt;
attr WR_1_API get41-8Name DigitalOutputs_TimeMode_RunTime&lt;br /&gt;
attr WR_1_API get41-9Name DigitalOutputs_TimeMode_StableTime&lt;br /&gt;
attr WR_1_API get41Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get41Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get41JSON .._value&lt;br /&gt;
attr WR_1_API get41Name 41_DigitalOutputs&lt;br /&gt;
attr WR_1_API get41URL http://%IP-WR%/api/v1/settings/devices:local/DigitalOutputs:Customer:ConfigurationFlags,DigitalOutputs:Customer:DelayTime,DigitalOutputs:Customer:PowerMode:OffPowerThreshold,DigitalOutputs:Customer:PowerMode:OnPowerThreshold,DigitalOutputs:Customer:SwitchOffDuration,DigitalOutputs:Customer:TimeMode:MaxNoOfSwitchingCyclesPerDay,DigitalOutputs:Customer:TimeMode:PowerThreshold,DigitalOutputs:Customer:TimeMode:RunTime,DigitalOutputs:Customer:TimeMode:StableTime&lt;br /&gt;
attr WR_1_API get51Name 51_modules_list&lt;br /&gt;
attr WR_1_API get51URL http://%IP-WR%/api/v1/modules&lt;br /&gt;
attr WR_1_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_1_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_1_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_1_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get60Name 60_update_status&lt;br /&gt;
attr WR_1_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_API icon sani_solar&lt;br /&gt;
attr WR_1_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_1_API reading0101JSON nonce&lt;br /&gt;
attr WR_1_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_1_API reading0102JSON rounds&lt;br /&gt;
attr WR_1_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_1_API reading0103JSON salt&lt;br /&gt;
attr WR_1_API reading0103Name auth_salt&lt;br /&gt;
attr WR_1_API reading0104JSON transactionId&lt;br /&gt;
attr WR_1_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_1_API reading0201JSON signature&lt;br /&gt;
attr WR_1_API reading0201Name auth_signature&lt;br /&gt;
attr WR_1_API reading0202JSON token&lt;br /&gt;
attr WR_1_API reading0202Name auth_token&lt;br /&gt;
attr WR_1_API reading0301JSON message&lt;br /&gt;
attr WR_1_API reading0301Name info_message&lt;br /&gt;
attr WR_1_API reading0302JSON error&lt;br /&gt;
attr WR_1_API reading0302Name info_error&lt;br /&gt;
attr WR_1_API reading03JSON sessionId&lt;br /&gt;
attr WR_1_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_1_API reading25Name Battery_EM_State&lt;br /&gt;
attr WR_1_API reading25OMap 0:Normal,8:Ruhe1,16:Ruhe2,32:Ausgleichsladung,64:Tiefentladeschutz&lt;br /&gt;
attr WR_1_API reading25Regex EM_State.*value&amp;quot;:(\d+)&lt;br /&gt;
attr WR_1_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_1_API replacement01Mode expression&lt;br /&gt;
attr WR_1_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_1_API replacement01Value {ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_1_API replacement02Mode expression&lt;br /&gt;
attr WR_1_API replacement02Regex %START%&lt;br /&gt;
attr WR_1_API replacement02Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_1_API replacement04Mode expression&lt;br /&gt;
attr WR_1_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_1_API replacement04Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_1_API replacement05Mode expression&lt;br /&gt;
attr WR_1_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_1_API replacement05Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_1_API replacement06Mode reading&lt;br /&gt;
attr WR_1_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_1_API replacement06Value auth_signature&lt;br /&gt;
attr WR_1_API replacement07Mode reading&lt;br /&gt;
attr WR_1_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_1_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_1_API replacement08Mode expression&lt;br /&gt;
attr WR_1_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_1_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_1_API replacement09Mode expression&lt;br /&gt;
attr WR_1_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_1_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_1_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set06Method POST&lt;br /&gt;
attr WR_1_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_1_API set06NoArg 1&lt;br /&gt;
attr WR_1_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_1_API set2201Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:DynamicSoc:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2201FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2201Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2201Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2201Hint 0,1&lt;br /&gt;
attr WR_1_API set2201Method PUT&lt;br /&gt;
attr WR_1_API set2201Name 22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
attr WR_1_API set2201URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2203Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinHomeComsumption&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2203FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2203Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2203Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2203Hint slider,50,50,8000&lt;br /&gt;
attr WR_1_API set2203Method PUT&lt;br /&gt;
attr WR_1_API set2203Name 22_03_Battery_MinHomeConsumption&lt;br /&gt;
attr WR_1_API set2203URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2204Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinSoc&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2204FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2204Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2204Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2204Hint slider,5,5,100&lt;br /&gt;
attr WR_1_API set2204Method PUT&lt;br /&gt;
attr WR_1_API set2204Name 22_04_Battery_MinSoc&lt;br /&gt;
attr WR_1_API set2204URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2205Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:SmartBatteryControl:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2205FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2205Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2205Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2205Hint 0,1&lt;br /&gt;
attr WR_1_API set2205Method PUT&lt;br /&gt;
attr WR_1_API set2205Name 22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr WR_1_API set2205URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2206Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Strategy&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2206FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2206Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2206Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2206Hint 1,2&lt;br /&gt;
attr WR_1_API set2206Method PUT&lt;br /&gt;
attr WR_1_API set2206Name 22_06_Battery_Strategy&lt;br /&gt;
attr WR_1_API set2206URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2207Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Type&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2207FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2207Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2207Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2207Hint 0,4&lt;br /&gt;
attr WR_1_API set2207Method PUT&lt;br /&gt;
attr WR_1_API set2207Name 22_07_Battery_Type&lt;br /&gt;
attr WR_1_API set2207URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2300Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2300FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2300Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2300Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2300Hint 0,1,2&lt;br /&gt;
attr WR_1_API set2300Method PUT&lt;br /&gt;
attr WR_1_API set2300Name 23_00_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2300URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2301Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:AcPowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2301FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2301Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2301Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2301Method PUT&lt;br /&gt;
attr WR_1_API set2301Name 23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
attr WR_1_API set2301URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2302Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:AcPowerRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2302FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2302Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2302Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2302Method PUT&lt;br /&gt;
attr WR_1_API set2302Name 23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
attr WR_1_API set2302URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2303Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcCurrentAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2303FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2303Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2303Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2303Method PUT&lt;br /&gt;
attr WR_1_API set2303Name 23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
attr WR_1_API set2303URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2304Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcCurrentRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2304FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2304Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2304Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2304Method PUT&lt;br /&gt;
attr WR_1_API set2304Name 23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
attr WR_1_API set2304URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2305Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcPowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2305FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2305Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2305Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2305Method PUT&lt;br /&gt;
attr WR_1_API set2305Name 23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
attr WR_1_API set2305URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2306Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcPowerRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2306FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2306Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2306Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2306Method PUT&lt;br /&gt;
attr WR_1_API set2306Name 23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
attr WR_1_API set2306URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2307Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxChargePowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2307FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2307Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2307Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2307Method PUT&lt;br /&gt;
attr WR_1_API set2307Name 23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
attr WR_1_API set2307URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2308Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxDischargePowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2308FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2308Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2308Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2308Method PUT&lt;br /&gt;
attr WR_1_API set2308Name 23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
attr WR_1_API set2308URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2309Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxSocRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2309FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2309Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2309Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2309Hint slider,30,5,100&lt;br /&gt;
attr WR_1_API set2309Method PUT&lt;br /&gt;
attr WR_1_API set2309Name 23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
attr WR_1_API set2309URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2310Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MinSocRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2310FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2310Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2310Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2310Hint slider,0,5,100&lt;br /&gt;
attr WR_1_API set2310Method PUT&lt;br /&gt;
attr WR_1_API set2310Name 23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
attr WR_1_API set2310URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2311Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ComMonitor:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2311FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2311Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2311Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2311Hint 0,1&lt;br /&gt;
attr WR_1_API set2311Method PUT&lt;br /&gt;
attr WR_1_API set2311Name 23_11_Battery_ComMonitor_Enable&lt;br /&gt;
attr WR_1_API set2311URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2312Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ComMonitor:Time&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2312FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2312Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2312Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2312Hint slider,0,10,600&lt;br /&gt;
attr WR_1_API set2312Method PUT&lt;br /&gt;
attr WR_1_API set2312Name 23_12_Battery_ComMonitor_Time&lt;br /&gt;
attr WR_1_API set2312URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set4002FollowGet 40_Generator_und EnergieMgmt&lt;br /&gt;
attr WR_1_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_1_API set4002Method PUT&lt;br /&gt;
attr WR_1_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set4101Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:DelayTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;5&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:PowerMode:OnPowerThreshold&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;100000&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:MaxNoOfSwitchingCyclesPerDay&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:PowerThreshold&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:RunTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;30&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:StableTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set4101FollowGet 41_DigitalOutputs&lt;br /&gt;
attr WR_1_API set4101Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set4101Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set4101Hint 0,9,13,14&lt;br /&gt;
attr WR_1_API set4101Method PUT&lt;br /&gt;
attr WR_1_API set4101Name 41_01_DigitalOutputs&lt;br /&gt;
attr WR_1_API set4101URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_1_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_1_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_1_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_1_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_1_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_1_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_1_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_1_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_1_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_1_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_1_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_1_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_1_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_1_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_1_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_1_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_1_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_1_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_1_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_1_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_1_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_1_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_1_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_1_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_1_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_1_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_1_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_1_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_1_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_1_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_1_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_1_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_1_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_1_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_1_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_1_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_1_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_1_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_1_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_1_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_1_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_1_API set50JSON .&lt;br /&gt;
attr WR_1_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_1_API set50ParseResponse 1&lt;br /&gt;
attr WR_1_API set50TextArg 1&lt;br /&gt;
attr WR_1_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_1_API set6001Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set6001Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set6001Method POST&lt;br /&gt;
attr WR_1_API set6001Name 60_01_Reset_Wechselrichter&lt;br /&gt;
attr WR_1_API set6001NoArg 1&lt;br /&gt;
attr WR_1_API set6001URL http://%IP-WR%/api/v1/system/reboot&lt;br /&gt;
attr WR_1_API showBody 1&lt;br /&gt;
attr WR_1_API showError 1&lt;br /&gt;
attr WR_1_API sid01Data %START%&lt;br /&gt;
attr WR_1_API sid01ParseResponse 1&lt;br /&gt;
attr WR_1_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_1_API sid02Data %FINISH%&lt;br /&gt;
attr WR_1_API sid02ParseResponse 1&lt;br /&gt;
attr WR_1_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_1_API sid03Data %SESSION%&lt;br /&gt;
attr WR_1_API sid03ParseResponse 1&lt;br /&gt;
attr WR_1_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_1_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_1_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API sortby 112&lt;br /&gt;
attr WR_1_API stateFormat {\&lt;br /&gt;
 my $calcVal = 0;;\&lt;br /&gt;
 my $WR      = &amp;quot;WR_1&amp;quot;;;\&lt;br /&gt;
 my $YearBefore      = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
 my $YearPrevious    = ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
   $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(time_str2num(ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $QuarterBefore   = &amp;quot;LogDBRep_Statistic_previous_Quarter&amp;quot;;;\&lt;br /&gt;
 my $QuarterPrevious = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
 foreach my $i (1,2,3,4) {if (ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,&amp;quot;Q&amp;quot;.$i,0) eq &amp;quot;previous&amp;quot;){ $QuarterPrevious = &amp;quot;Q&amp;quot;.$i }};;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvt   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Total_AC_Active_P&amp;quot;,0) );;\&lt;br /&gt;
 my $pvtd  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvtm  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvtm .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_Yield&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvty  = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvty .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv    = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0) );;\&lt;br /&gt;
 my $pvd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomePv&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvy   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $gfi   =  sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0),0)):  0) );;\&lt;br /&gt;
 my $gfid  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $gfim  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $gfim .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomeFeedInGrid&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $gfiy  = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $gfiy .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $eb    = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0),0) : 0) );;\&lt;br /&gt;
 my $ebd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $ebm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $ebm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomeGrid&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $eby   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $eby  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvb   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0));;\&lt;br /&gt;
 my $pvbd  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvbm  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvbm .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, 158+ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_Statistic_EnergyHomeBat&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvby  = sprintf(&amp;quot;%05d&amp;quot;,158+ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvby .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $et    = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0)) );;\&lt;br /&gt;
 my $etd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $etm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $etm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_TotalConsumption&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $ety   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $ety  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $valA  = ReadingsVal($WR, &amp;quot;SW_Total_AC_Active_P&amp;quot;,0)-ReadingsVal($WR, &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0);;\&lt;br /&gt;
    $calcVal = ($valA &amp;gt; 0) ? round($valA /($valA + ReadingsVal($WR, &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0;;\&lt;br /&gt;
 my $aq    = sprintf(&amp;quot;%4d %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
 \&lt;br /&gt;
 my $aqd   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Day&amp;quot;,0) );;\&lt;br /&gt;
 my $aqm   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Month&amp;quot;,0) );;\&lt;br /&gt;
 my $aqy   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0) );;\&lt;br /&gt;
    $aqy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %3d %%&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $valS  = ReadingsVal($WR,&amp;quot;SW_Total_AC_Active_P&amp;quot;,0);;\&lt;br /&gt;
    $calcVal = ($valS &amp;gt; 0) ? round((ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0) + ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)) / $valS * 100 ,0) : 0;;\&lt;br /&gt;
 my $sq    =  sprintf(&amp;quot;%4d %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
\&lt;br /&gt;
 my $sqd   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Day&amp;quot;,0) );;\&lt;br /&gt;
 my $sqm   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Month&amp;quot;,0) );;\&lt;br /&gt;
 my $sqy   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Year&amp;quot;,0) );;\&lt;br /&gt;
    $sqy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %3d %%&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $date  = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;auth_me_authenticated&amp;quot;,0))));;\&lt;br /&gt;
 my $md    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;auth_me_authenticated&amp;quot;,0))));;\&lt;br /&gt;
 my $cd    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Day&amp;quot;,0))));;\&lt;br /&gt;
 my $cm    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Month&amp;quot;,0))));;\&lt;br /&gt;
    $cm   .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.POSIX::strftime(&amp;quot;%d.%m&amp;quot;,localtime(time_str2num(ReadingsTimestamp(&amp;quot;$QuarterBefore&amp;quot;,&amp;quot;$QuarterPrevious&amp;quot;,0) ))) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $cy    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0))));;\&lt;br /&gt;
    $cy   .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.$YearPrevious : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Statistik vom $date in kWh&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;aktuell&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Monat&amp;quot;.(($QuarterPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.$QuarterPrevious : &amp;quot;&amp;quot;).&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Jahr&amp;quot;.(($YearPrevious ne &amp;quot;0&amp;quot;) ? &amp;quot; / Vorjahr&amp;quot; : &amp;quot;&amp;quot;).&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Erzeugung PV-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug von PV&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug von Batterie&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvbd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvbm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug ins Haus (Energieverbrauch)&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug vom Netz&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Einspeisung ins Netz&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnet um&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr WR_1_API timeout 7&lt;br /&gt;
attr WR_1_API userReadings Statistic_EnergyHomePvSum_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;0&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;0&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;0&amp;quot;) ),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)),0)},\&lt;br /&gt;
Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)),0)},\&lt;br /&gt;
Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyPv1_Day:Statistic_EnergyPv1_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Month:Statistic_EnergyPv1_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Total:Statistic_EnergyPv1_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Year:Statistic_EnergyPv1_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Day:Statistic_EnergyPv2_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Month:Statistic_EnergyPv2_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Total:Statistic_EnergyPv2_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Year:Statistic_EnergyPv2_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Day:Statistic_EnergyPv3_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Month:Statistic_EnergyPv3_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Total:Statistic_EnergyPv3_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Year:Statistic_EnergyPv3_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyPv4_Day:Statistic_EnergyPv1_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Month:Statistic_EnergyPv1_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Total:Statistic_EnergyPv1_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Year:Statistic_EnergyPv1_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Day:Statistic_EnergyPv2_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Month:Statistic_EnergyPv2_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Total:Statistic_EnergyPv2_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Year:Statistic_EnergyPv2_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Day:Statistic_EnergyPv3_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Month:Statistic_EnergyPv3_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Total:Statistic_EnergyPv3_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Year:Statistic_EnergyPv3_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Yield_Day:Statistic_Yield_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Total:Statistic_Yield_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Total&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)),0)},\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)),0)},\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Day:SW_Statistic_Yield_Day.* {   (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Day&amp;quot;  ,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Month:SW_Statistic_Yield_Month.* { (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Month&amp;quot;,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Year:SW_Statistic_Yield_Year.* {  (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Year&amp;quot; ,0)) * 1000 },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Day:SW_Statistic_Yield_Day.* {   (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Day&amp;quot;  ,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Month:SW_Statistic_Yield_Month.* { (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Month&amp;quot;,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Year:SW_Statistic_Yield_Year.* {  (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Year&amp;quot; ,0)) * 1000 },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;  ,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot; ,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {   round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHome_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0) },\&lt;br /&gt;
SW_Statistic_EnergyHome_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) },\&lt;br /&gt;
SW_Statistic_EnergyHome_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_TotalConsumption_Day:SW_Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Day&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;,0) ) ,0)},\&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0)},\&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Autarky_Day:SW_Statistic_EnergyHomePvSum_Day.* { my $SW_Statistic_EnergyHome_Day = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Day&amp;quot;,0) ;; ($SW_Statistic_EnergyHome_Day eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Day&amp;quot;,0) / $SW_Statistic_EnergyHome_Day *100,0) },\&lt;br /&gt;
SW_Statistic_Autarky_Month:SW_Statistic_EnergyHomePvSum_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Month&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Month&amp;quot;,0) *100,0) },\&lt;br /&gt;
SW_Statistic_Autarky_Year:SW_Statistic_EnergyHomePvSum_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Year&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Year&amp;quot;,0) *100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Day:SW_Statistic_EnergyHomePvSum_Day.* {my $SW_Statistic_Yield_Day = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Day eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Day&amp;quot;  ,0) / $SW_Statistic_Yield_Day*100,0) },\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Month:SW_Statistic_EnergyHomePvSum_Month.* {my $SW_Statistic_Yield_Month = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Month eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Month&amp;quot;  ,0) / $SW_Statistic_Yield_Month*100,0) },\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Year:SW_Statistic_EnergyHomePvSum_Year.* {my $SW_Statistic_Yield_Year = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Year eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Year&amp;quot;  ,0) / $SW_Statistic_Yield_Year*100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyChargeGrid_Total:Statistic_EnergyChargeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyChargeInvIn_Total:Statistic_EnergyChargeInvIn_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargeInvIn_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyChargePv_Total:Statistic_EnergyChargePv_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargePv_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyDischargeGrid_Total:Statistic_EnergyDischargeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyDischargeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyDischarge_Total:Statistic_EnergyDischarge_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyDischarge_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeBat_Total:Statistic_EnergyHomeBat_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Total:Statistic_EnergyHomeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeOwn_Total:Statistic_EnergyHomeOwn_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeOwn_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Total:Statistic_EnergyHomePv_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHome_Total:Statistic_EnergyHome_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHome_Total&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Autarky_Total:SW_Statistic_EnergyHomePv_Total.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Total&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Total&amp;quot;,0) *100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Total:SW_Statistic_EnergyHomePv_Total.* {my $SW_Statistic_Yield_Total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Total&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Total eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Total&amp;quot; ,0) / $SW_Statistic_Yield_Total*100,0) }&lt;br /&gt;
attr WR_1_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erweiterung im PV_Schedule, um die Zählerstände zu speichern&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 1)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_2_API DbLogExclude .*&lt;br /&gt;
attr WR_2_API DbLogInclude Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API authRetries 1&lt;br /&gt;
attr WR_2_API comment Version 2021.04.27 16:00\&lt;br /&gt;
Passworte für die Abfrage des WR_2_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_2_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_2_API disable 0&lt;br /&gt;
attr WR_2_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_2_API enableControlSet 0&lt;br /&gt;
attr WR_2_API enableCookies 1&lt;br /&gt;
attr WR_2_API event-on-update-reading auth_.*,Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API get01Data %START%&lt;br /&gt;
attr WR_2_API get01Name 01_auth_start&lt;br /&gt;
attr WR_2_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API get02Data %FINISH%&lt;br /&gt;
attr WR_2_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_2_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API get03Data %SESSION%&lt;br /&gt;
attr WR_2_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_2_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_2_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_2_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_2_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_2_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_2_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_2_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get04JSON .&lt;br /&gt;
attr WR_2_API get04Name 04_auth_me&lt;br /&gt;
attr WR_2_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_2_API get05-1Name info_api_version&lt;br /&gt;
attr WR_2_API get05-2Name info_hostname&lt;br /&gt;
attr WR_2_API get05-3Name info_name&lt;br /&gt;
attr WR_2_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_2_API get05JSON .&lt;br /&gt;
attr WR_2_API get05Name 05_info_version&lt;br /&gt;
attr WR_2_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_2_API get20-10Format %.2f&lt;br /&gt;
attr WR_2_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-11Format %.2f&lt;br /&gt;
attr WR_2_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-12Format %.2f&lt;br /&gt;
attr WR_2_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-13Format %.2f&lt;br /&gt;
attr WR_2_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_2_API get20-14Format %.2f&lt;br /&gt;
attr WR_2_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_2_API get20-15Format %.2f&lt;br /&gt;
attr WR_2_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_2_API get20-16Format %.2f&lt;br /&gt;
attr WR_2_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_2_API get20-17Format %.2f&lt;br /&gt;
attr WR_2_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_2_API get20-18Format %.2f&lt;br /&gt;
attr WR_2_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_2_API get20-19Format %.2f&lt;br /&gt;
attr WR_2_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_2_API get20-1Format %.2f&lt;br /&gt;
attr WR_2_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_2_API get20-20Format %.2f&lt;br /&gt;
attr WR_2_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_2_API get20-21Format %.2f&lt;br /&gt;
attr WR_2_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_2_API get20-22Format %.2f&lt;br /&gt;
attr WR_2_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_2_API get20-23Format %.2f&lt;br /&gt;
attr WR_2_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_2_API get20-24Format %.2f&lt;br /&gt;
attr WR_2_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_2_API get20-25Format %.2f&lt;br /&gt;
attr WR_2_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_2_API get20-26Format %.2f&lt;br /&gt;
attr WR_2_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-27Format %.2f&lt;br /&gt;
attr WR_2_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-28Format %.2f&lt;br /&gt;
attr WR_2_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-29Format %.2f&lt;br /&gt;
attr WR_2_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_2_API get20-2Format %.2f&lt;br /&gt;
attr WR_2_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_2_API get20-30Format %.2f&lt;br /&gt;
attr WR_2_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_2_API get20-31Format %.2f&lt;br /&gt;
attr WR_2_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_2_API get20-32Format %.2f&lt;br /&gt;
attr WR_2_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_2_API get20-33Format %.2f&lt;br /&gt;
attr WR_2_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_2_API get20-34Format %.2f&lt;br /&gt;
attr WR_2_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_2_API get20-35Format %.2f&lt;br /&gt;
attr WR_2_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_2_API get20-36Format %.2f&lt;br /&gt;
attr WR_2_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_2_API get20-37Format %.2f&lt;br /&gt;
attr WR_2_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_2_API get20-38Format %.2f&lt;br /&gt;
attr WR_2_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_2_API get20-39Format %.2f&lt;br /&gt;
attr WR_2_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_2_API get20-3Format %.2f&lt;br /&gt;
attr WR_2_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_2_API get20-40Format %.2f&lt;br /&gt;
attr WR_2_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_2_API get20-41Format %.2f&lt;br /&gt;
attr WR_2_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_2_API get20-42Format %.2f&lt;br /&gt;
attr WR_2_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_2_API get20-43Format %.2f&lt;br /&gt;
attr WR_2_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_2_API get20-44Format %.2f&lt;br /&gt;
attr WR_2_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_2_API get20-45Format %.2f&lt;br /&gt;
attr WR_2_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_2_API get20-46Format %.2f&lt;br /&gt;
attr WR_2_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_2_API get20-47Format %.2f&lt;br /&gt;
attr WR_2_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_2_API get20-48Format %.2f&lt;br /&gt;
attr WR_2_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_2_API get20-49Format %.2f&lt;br /&gt;
attr WR_2_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_2_API get20-4Format %.2f&lt;br /&gt;
attr WR_2_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_2_API get20-50Format %.2f&lt;br /&gt;
attr WR_2_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_2_API get20-51Format %.2f&lt;br /&gt;
attr WR_2_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_2_API get20-52Format %.2f&lt;br /&gt;
attr WR_2_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_2_API get20-53Format %.2f&lt;br /&gt;
attr WR_2_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_2_API get20-54Format %.2f&lt;br /&gt;
attr WR_2_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_2_API get20-55Format %.2f&lt;br /&gt;
attr WR_2_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_2_API get20-56Format %.2f&lt;br /&gt;
attr WR_2_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_2_API get20-57Format %.2f&lt;br /&gt;
attr WR_2_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_2_API get20-58Format %.2f&lt;br /&gt;
attr WR_2_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_2_API get20-59Format %.2f&lt;br /&gt;
attr WR_2_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_2_API get20-5Format %.2f&lt;br /&gt;
attr WR_2_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_2_API get20-60Format %.2f&lt;br /&gt;
attr WR_2_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_2_API get20-61Format %.2f&lt;br /&gt;
attr WR_2_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_2_API get20-62Format %.2f&lt;br /&gt;
attr WR_2_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_2_API get20-63Format %.2f&lt;br /&gt;
attr WR_2_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_2_API get20-64Format %.2f&lt;br /&gt;
attr WR_2_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_2_API get20-65Format %.2f&lt;br /&gt;
attr WR_2_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_2_API get20-6Format %.2f&lt;br /&gt;
attr WR_2_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_2_API get20-7Format %.2f&lt;br /&gt;
attr WR_2_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_2_API get20-8Format %.2f&lt;br /&gt;
attr WR_2_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_2_API get20-9Format %.2f&lt;br /&gt;
attr WR_2_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_2_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_2_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_2_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_2_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get40Name 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable&lt;br /&gt;
attr WR_2_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_2_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_2_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_2_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get60Name 60_update_status&lt;br /&gt;
attr WR_2_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_2_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_2_API icon sani_solar&lt;br /&gt;
attr WR_2_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_2_API reading0101JSON nonce&lt;br /&gt;
attr WR_2_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_2_API reading0102JSON rounds&lt;br /&gt;
attr WR_2_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_2_API reading0103JSON salt&lt;br /&gt;
attr WR_2_API reading0103Name auth_salt&lt;br /&gt;
attr WR_2_API reading0104JSON transactionId&lt;br /&gt;
attr WR_2_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_2_API reading0201JSON signature&lt;br /&gt;
attr WR_2_API reading0201Name auth_signature&lt;br /&gt;
attr WR_2_API reading0202JSON token&lt;br /&gt;
attr WR_2_API reading0202Name auth_token&lt;br /&gt;
attr WR_2_API reading0301JSON message&lt;br /&gt;
attr WR_2_API reading0301Name info_message&lt;br /&gt;
attr WR_2_API reading0302JSON error&lt;br /&gt;
attr WR_2_API reading0302Name info_error&lt;br /&gt;
attr WR_2_API reading03JSON sessionId&lt;br /&gt;
attr WR_2_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_2_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_2_API replacement01Mode expression&lt;br /&gt;
attr WR_2_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_2_API replacement01Value {ReadingsVal(&amp;quot;WR_2_config&amp;quot;,&amp;quot;IP-WR_2&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement02Mode expression&lt;br /&gt;
attr WR_2_API replacement02Regex %START%&lt;br /&gt;
attr WR_2_API replacement02Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement04Mode expression&lt;br /&gt;
attr WR_2_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_2_API replacement04Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement05Mode expression&lt;br /&gt;
attr WR_2_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_2_API replacement05Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement06Mode reading&lt;br /&gt;
attr WR_2_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_2_API replacement06Value auth_signature&lt;br /&gt;
attr WR_2_API replacement07Mode reading&lt;br /&gt;
attr WR_2_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_2_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_2_API replacement08Mode expression&lt;br /&gt;
attr WR_2_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_2_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API replacement09Mode expression&lt;br /&gt;
attr WR_2_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_2_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set06Method POST&lt;br /&gt;
attr WR_2_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_2_API set06NoArg 1&lt;br /&gt;
attr WR_2_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_2_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_2_API set4002FollowGet 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_2_API set4002Method PUT&lt;br /&gt;
attr WR_2_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_2_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_2_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_2_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_2_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_2_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_2_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_2_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_2_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_2_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_2_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_2_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_2_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_2_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_2_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_2_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_2_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_2_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_2_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_2_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_2_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_2_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_2_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_2_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_2_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_2_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_2_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_2_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_2_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_2_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_2_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_2_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_2_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_2_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_2_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_2_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_2_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_2_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_2_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_2_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_2_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_2_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_2_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_2_API set50JSON .&lt;br /&gt;
attr WR_2_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_2_API set50ParseResponse 1&lt;br /&gt;
attr WR_2_API set50TextArg 1&lt;br /&gt;
attr WR_2_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_2_API showBody 1&lt;br /&gt;
attr WR_2_API showError 1&lt;br /&gt;
attr WR_2_API sid01Data %START%&lt;br /&gt;
attr WR_2_API sid01ParseResponse 1&lt;br /&gt;
attr WR_2_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API sid02Data %FINISH%&lt;br /&gt;
attr WR_2_API sid02ParseResponse 1&lt;br /&gt;
attr WR_2_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API sid03Data %SESSION%&lt;br /&gt;
attr WR_2_API sid03ParseResponse 1&lt;br /&gt;
attr WR_2_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API sortby 212&lt;br /&gt;
attr WR_2_API timeout 7&lt;br /&gt;
attr WR_2_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion Solar_forecast() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive        An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning       Aus = momentan keine Steuerung&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0          0 = Es gibt kein Mittags Hoch. Wird aus Solar_forecast() gesetzt &lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der PV_1:Solar_middayhigh_fc0_start wird dann unlimitiert bis zur PV_1:Solar_middayhigh_fc0_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_ExternControl DOIF ################################################################################################################\&lt;br /&gt;
## 1 Speicher Status vom WR_1_Speicher_1 aktualisieren.\&lt;br /&gt;
##   Dies geschieht über das WR_1_API Device, da der Speicher direkt am Wechselrichter angeschlossen ist.\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_WR_1_Speicher_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [:52]                                                           ## jede Stunde\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 21_Battery_Information&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 22_Battery_InternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 23_Battery_ExternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_1  : Speicher Status abfrage&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Wenn die Ladung im Herbst/Winter unter MinSoc geht allen PV Überschuss in die Batterie laden\&lt;br /&gt;
##\&lt;br /&gt;
## Im Winter kann der MinSoc, durch den WR Eigenverbrauch, unterschritten werden, deshalb wird vorher auf\&lt;br /&gt;
## smarte_laden umgeschaltet, bis die Batterie wieder einen hohen Soc erreicht hat. Siehe cmd_3 laden_beendet\&lt;br /&gt;
##\&lt;br /&gt;
2_smart_Laden_start_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [WR_ctl:Yield_fc0_day] &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit]     ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
       and [WR_1:Act_state_of_charge] &amp;lt;= [WR_1_API:Battery_InternControl_MinSoc]  ## Achtung der Speicherstand wird zu niedrig\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100             ## Der Speicher steht auf Entladen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.1: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.1: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_smart_Laden_start_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [WB_1:lp_1_ChargeStat]      eq &amp;quot;loading&amp;quot;                        ## Ein Fahrzeug wird gerade geladen\&lt;br /&gt;
     and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;Aus&amp;quot;                            ## Der Speicher darf nicht zum Laden verwendet werden\&lt;br /&gt;
     or\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot;                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot; ) {\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before aktiv&amp;quot;);;                ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before inaktiv&amp;quot;);;              ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
    } else {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_2.2: WallBox es wird gerade geladen&amp;quot;};;       ## Der vorherige Zustand war schon bekannt\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.2: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.2: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Beim erreichen von 90% Soc die Entladung wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:SpeicherEntladung] eq &amp;quot;Automatik&amp;quot;                            ## Nur für den Automatik Modus\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100         ## Das Speicher Entladen ist geperrt\&lt;br /&gt;
       and\&lt;br /&gt;
       [WR_1:Act_state_of_charge] &amp;gt;= 80                                  ## Der Speicher ist bereits 80% voll\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell aktiviert\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.1: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.1: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_smart_Laden_beenden_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;inaktiv&amp;quot;                      ## Vorher war es nicht aktiv\&lt;br /&gt;
      )\&lt;br /&gt;
     or  [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;                             ## Der Speicher darf zum Laden verwendet werden\&lt;br /&gt;
     or  [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                       ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.2: Batterie wird mit &amp;quot;.[?$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.2: Batterie auf &amp;quot;.[?WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (    [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;\&lt;br /&gt;
        and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;) {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF cmd_3.2: MaxSOC Limitierung wegen Wallboxnutzung abgeschaltet&amp;quot;;;}\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Wenn vor dem WB_1 laden das smart_Laden aktiv gewesen ist geht es zurück in den Zustand\&lt;br /&gt;
## \&lt;br /&gt;
3_smart_Laden_umschalten_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;aktiv&amp;quot;                        ## Vorher war es nicht aktiv\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_umschalten_WB_1&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                        ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: WB_1 laden beendet, reaktivieren des smart_Laden&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.3: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.3: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Bei Zeitsteuerung und guter Prognose bei 40% wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Zeit\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [$SELF:SpeicherEntladung]  eq &amp;quot;Zeit&amp;quot;                            ## Nur für den Zeit Modus\&lt;br /&gt;
     and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]            ## Zeitfenster aktiv ist\&lt;br /&gt;
     and [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                        ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (\&lt;br /&gt;
            [WR_1:Act_state_of_charge] &amp;gt;= 40                             ## und einem Stand von Soc 40%\&lt;br /&gt;
        and\&lt;br /&gt;
            ([WR_ctl:Yield_fc0_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit]   ## wenn es heute oder \&lt;br /&gt;
          or [WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit])  ## morgen viel Leistung gibt\&lt;br /&gt;
       )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_zeit&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, SpeicherExternTrigger, freigegeben&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Die Leistungsprognose von &amp;quot;.[$SELF:SpeicherMinSOC_fc1_Limit].&amp;quot; wird überschritten&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;frei&amp;quot;);;                         ## Trigger freigeben\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                           ## Signalisiere entladen im stateFormat\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);; ## Speicher für Entladung freigeben\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Freigabe der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. ([07:00-16:00]\&lt;br /&gt;
4_Trigger\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]       ## Zeitfenster aktiv ist\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot;                               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot; ) {                             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;  ## Speicher für Entladung freigeben\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                            ## Signalisiere entladen im stateFormat\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_4  : SpeicherExternTrigger, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Sperren der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. [16:00-07:00]\&lt;br /&gt;
5_Trigger_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitEnde]-[$SELF:SpeicherZeitStart]]       ## Zeitfenster verlassen wurde\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger_sperren&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;## Speicher für Entladung sperren\&lt;br /&gt;
  set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                             ## Signalisiere gesperrt im stateFormat\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
    {Log 3, &amp;quot;$SELF cmd_5  : SpeicherExternTrigger, Entlademodus gesperrt (Tarif oder Trigger)&amp;quot;};;\&lt;br /&gt;
 }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
6_Kommando_Wiederholung\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [WR_1_API:Battery_Control] &amp;gt; 0 and                                ## Wenn die ExternControl am WR konfiguriert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatActive]  eq &amp;quot;An&amp;quot; and                      ## Wenn die ExternControl Aktiviert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatRunning] eq &amp;quot;An&amp;quot; and                      ## Wenn es  ExternControl Kommandos zum Senden gibt\&lt;br /&gt;
       [  {sunrise_abs(&amp;quot;HORIZON=+5.0&amp;quot;,0,&amp;quot;6:00&amp;quot;,&amp;quot;08:35&amp;quot;)}                 ## Innerhalb der Photovoltaik Zeit\&lt;br /&gt;
        - {sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)} ] and\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot; ) {              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   my $MaxChargePowerTime = 0;;\&lt;br /&gt;
   my $MaxChargePowerAbs_midday = 0;;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {                              ## Hier können noch Testmeldungen hin\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : SpeicherMiddayControlRunning &amp;quot;.[$SELF:SpeicherMiddayControlRunning];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_start   &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_stop    &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop];;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlRunning] eq &amp;quot;An&amp;quot; ) {                  ## Wurde ein Mittagshoch ermittelt und aktiviert?\&lt;br /&gt;
\&lt;br /&gt;
     if ( [WR_1:Act_state_of_charge] &amp;gt;= [WR_1_API:Battery_InternControl_MinSoc] *3 ) {\&lt;br /&gt;
       if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs 0&amp;quot;);;     ## nicht vor z.B. 09:00 Uhr starten. Ladung auf 0 Watt setzen\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                                              ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot; Uhr noch nicht laden&amp;quot;;;\&lt;br /&gt;
         }\&lt;br /&gt;
       } else {                                                          ## Ist noch Vormittag?\&lt;br /&gt;
         if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
           ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning]);;\&lt;br /&gt;
           set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMidday_MaxSOC].&#039;)&#039;);;\&lt;br /&gt;
           if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                       ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; limitieren&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning].&amp;quot; limitiert&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSOC auf &amp;quot;.[$SELF:SpeicherMidday_MaxSOC].&amp;quot; % limitiert&amp;quot;;;\&lt;br /&gt;
           }\&lt;br /&gt;
         }\&lt;br /&gt;
       }\&lt;br /&gt;
     } else {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_6  : Battery_InternControl_MinSoc auf &amp;quot;.([WR_1_API:Battery_InternControl_MinSoc] *3).&amp;quot; % laden&amp;quot;;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
     if (::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) &amp;lt;= time and  ## Es ist Mittag\&lt;br /&gt;
         time &amp;lt;= ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
\&lt;br /&gt;
       my $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;)+3600 ));;\&lt;br /&gt;
          $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ));;\&lt;br /&gt;
\&lt;br /&gt;
       if ([$SELF:SpeicherMaxSOCControlRunning] eq &amp;quot;An&amp;quot; and                     ## Somit bleibt weniger Platz im Speicher und es ist\&lt;br /&gt;
           time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.$wait.&amp;quot;:00&amp;quot;) ) {  ## besser nicht zu früh beginnen.\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden wegen MaxSoc von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; auf &amp;quot;.$wait.&amp;quot; Uhr verschoben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
       } else {                                                                 ## auch jetzt nicht mit voller Leistung laden\&lt;br /&gt;
\&lt;br /&gt;
         if ([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0) {            ## dynamische Leistungsermittlung oder vorgewählter Wert\&lt;br /&gt;
           $MaxChargePowerTime       = ::round((::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) - time) / 3600 , 2);;  ## Mittags Ladezeit bestimmen\&lt;br /&gt;
\&lt;br /&gt;
           my $MaxChargePowerLimit   = (1 - ::round($MaxChargePowerTime,2) * [$SELF:SpeicherMidday_MaxChargePowerSteigung]);;  ## Zu Beginn etwas langsamer anfangen, empirisch ermittelt\&lt;br /&gt;
\&lt;br /&gt;
           $MaxChargePowerAbs_midday = ::round( [WR_1:Battery_work_capacity] * ([$SELF:SpeicherMaxSOC_Actual] - [WR_1:Act_state_of_charge]) / 100 * $MaxChargePowerLimit, 0);;\&lt;br /&gt;
\&lt;br /&gt;
           if ($MaxChargePowerAbs_midday &amp;lt; 500) { $MaxChargePowerAbs_midday = 500 };;## Nicht unter 1000\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Mittags $MaxChargePowerTime h mit $MaxChargePowerAbs_midday W laden&amp;quot;;;\&lt;br /&gt;
         } else {\&lt;br /&gt;
           $MaxChargePowerAbs_midday = [$SELF:SpeicherMidday_MaxChargePowerAbs_midday];; ## Nimm den vorgewählten Wert\&lt;br /&gt;
         };;\&lt;br /&gt;
\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs $MaxChargePowerAbs_midday&amp;quot;);;\&lt;br /&gt;
         set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMaxSOC_Actual].&#039;)&#039;);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; bis &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; freigegeben&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf $MaxChargePowerAbs_midday limitiert&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;\&lt;br /&gt;
         };;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
\&lt;br /&gt;
     if (time &amp;gt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {    ## Es ist Nachmittag und die\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                                         ## Mittagssteuerung wird abgeschaltet\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl nach &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; beendet&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;An&amp;quot; and ## Nur MaxSOC soll begrenzt werden\&lt;br /&gt;
       [$SELF:SpeicherMaxSOC_Actual] &amp;lt;= 100                        and                                          \&lt;br /&gt;
       ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;Aus&amp;quot;) { ##  sobald die Mittagssteuerung fertig ist\&lt;br /&gt;
     if ([WR_1:SW_Home_own_consumption_from_Battery] &amp;gt; 500) {             ## Sollte der Speicher bereits jetzt verwendet werden ist es besser\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                 ## die MaxSOC Begrenzung zu stoppen\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMaxSOCControl wegen Speicher Nutzung am Nachmittag beendet&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_6  : ExternControl Kommando Wiederholung erledigt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Bestimmung eines möglichen SOC für den nächsten Morgen und\&lt;br /&gt;
##   Vorbereitung für ein Leistungshoch am Mittag\&lt;br /&gt;
##\&lt;br /&gt;
7_SOC_Calculation\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       ([WR_1_API:Battery_Control] &amp;gt; 0 and                               ## Ist die ExternControl am WR aktiviert\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot;   or                ## Ist MaxSOC Limit konfiguriert\&lt;br /&gt;
         [$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; ) and               ## Ist Midday Kontrolle konfiguriert\&lt;br /&gt;
        [$SELF:SpeicherMaxSOC_MinSOC_Time]  eq &amp;quot;NULL&amp;quot; and                ## Wurde ein minimum SOC bereits ermittelt\&lt;br /&gt;
        [{sunrise_abs(&amp;quot;HORIZON=+4.0&amp;quot;,0,&amp;quot;5:50&amp;quot;,&amp;quot;08:35&amp;quot;)} - 10:00 ] and\&lt;br /&gt;
        [WR_1:SW_Home_own_consumption_from_PV] == [WR_1:SW_Home_own_consumption] ## Die PV Leistung reicht für&#039;s Haus\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot; ) {                     ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   my $MinSOC_Time   = &amp;quot;gefunden&amp;quot;;;                                       ## Nur einmal am Tag bearbeiten\&lt;br /&gt;
   my $MinSOC_MinSOC = ::round([WR_1:Act_state_of_charge],0);;            ## Festgestellter MinSOC am Morgen          Magic ???\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,$MinSOC_Time);;\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,$MinSOC_MinSOC);;\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                               ## merken und melden\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_MinSOC_Time &amp;quot;.$MinSOC_Time.&amp;quot; &amp;quot;.$MinSOC_MinSOC.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot; and\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt; 100 and     ## Der Speicher darf nicht im smart_laden sein\&lt;br /&gt;
       [Pool_Counter:countsPerDay] == 0 and                              ## Achtung der Pool und auch die LWP\&lt;br /&gt;
       [LWP_Counter:countsPerDay]  == 0 ) {                              ##    sollten nicht mehr früh morgens laufen\&lt;br /&gt;
\&lt;br /&gt;
     my $SpeicherSOCMinimum = [WR_1_API:Battery_InternControl_MinSoc]*3;; ## 3x MinSOC als reserve vorsehen\&lt;br /&gt;
     my $SpeicherSOCDayBefore = ::round(ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;, 100),0);; ## wie voll war er gestern noch?\&lt;br /&gt;
     my $SpeicherSOCNew       = 0;;\&lt;br /&gt;
     my $SpeicherSOCDelta     = 0;;\&lt;br /&gt;
\&lt;br /&gt;
     if ([WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMaxSOC_fc1_Limit] and\&lt;br /&gt;
         $MinSOC_MinSOC                   &amp;gt; $SpeicherSOCMinimum ) {      ## Ist der Speicher voller als er müsste?\&lt;br /&gt;
\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Leistung Prognose &amp;quot;.[WR_ctl:Yield_fc1_day].&amp;quot; wh &amp;gt; Schwellwert &amp;quot;.[$SELF:SpeicherMaxSOC_fc1_Limit].&amp;quot; wh&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Speicherladung aktuell $MinSOC_MinSOC % &amp;gt; Minimum $SpeicherSOCMinimum %&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
       $SpeicherSOCDelta = $MinSOC_MinSOC - $SpeicherSOCMinimum;;         ## Was wäre noch übrig?\&lt;br /&gt;
       if ($SpeicherSOCDelta &amp;lt;= 10) {                                    ## Das lohnt sich nicht\&lt;br /&gt;
         $SpeicherSOCNew = $SpeicherSOCDayBefore;;                        ## den Wert von gestern einfach beibehalten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCDayBefore);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; % gesichert&amp;quot;};;\&lt;br /&gt;
       } else {\&lt;br /&gt;
         $SpeicherSOCNew = ::round(($SpeicherSOCDayBefore+$SpeicherSOCDayBefore-$SpeicherSOCDelta)/2 ,0);;  ## um den Durchschnitt verringern\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCNew);;           ## Das soll heute in den Speicher\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCNew.&amp;quot; % neu berechnet und gesichert&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
       if ($SpeicherSOCNew &amp;gt; 0) {                                        ## Es gibt einen neuen MaxSoc\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;               ## Senden starten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Wiederholung starten\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual &amp;quot;.$SpeicherSOCNew.&amp;quot; % geplant&amp;quot;};;\&lt;br /&gt;
       } else {                                                          ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
     } else {                                                            ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
       if ($MinSOC_MinSOC  &amp;lt; $SpeicherSOCMinimum ) {                     ## MaxSoc leicht erhöhen, da er etwas zu niedrig war\&lt;br /&gt;
         $SpeicherSOCNew   = ::round($SpeicherSOCDayBefore+$SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         $SpeicherSOCDelta = ::round($SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,$SpeicherSOCNew);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore wurde um &amp;quot;.$SpeicherSOCDelta.&amp;quot; erhöht&amp;quot;};;\&lt;br /&gt;
       }\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt, da die Prognose für morgen zu schlecht ist&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; and                   ## Soll für mittags noch Platz gehalten werden?\&lt;br /&gt;
       [WR_ctl:Yield_fc0_middayhigh] == 1 ) {                                                    \&lt;br /&gt;
																	                           \&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Die Mittagskontrolle aktivieren\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){                              ## (die Uhrzeiten wurden bereits durch Solar_forecast() im WR_1 Device eingetragen)\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie SpeicherMiddayControlRunning vorbereitet&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_start &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_start&amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_stop  &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_stop &amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {                                                              ## Kein Mittagshoch\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMiddayControl es wird kein Middayhigh geben&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Reset der ExternControl Kommandos\&lt;br /&gt;
##\&lt;br /&gt;
8_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;16:00&amp;quot;,&amp;quot;21:00&amp;quot;)}]                ## hier sollte das Ende der PV-Zeit sein\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot;                                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot; ) {                               ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
																			                   \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Max SOC Steuerung zurücksetzen\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                           ## SpeicherMaxSOC_Actual auf Default\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,[WR_1:Act_state_of_charge]);;   ## Den vor Tages Wert merken\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,&amp;quot;NULL&amp;quot;);;                     ## Die MinSOC Time löschen\&lt;br /&gt;
																						       \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Midday Steuerung zurücksetzen\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_8  : ExternControl zurückgesetzt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird, das ist dann im Herbst/Winter\&lt;br /&gt;
##\&lt;br /&gt;
9_MinSOC_Winter\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit] and        ## Wenn morgen das Minimum an Leistung nicht erreicht wird\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;lt; [$SELF:SpeicherMinSOC_Winter]    and        ## und der MinSoc unter der Winter Wert eingestellt ist\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot; or\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;NULL&amp;quot; and [10:01])\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Winter]);;        ## Den MinSOC anheben, um eine eventuelle\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : Batterie MinSoc auf Winterbetrieb&amp;quot;};;        ## Notladung zu verhindern\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Im Winter Betrieb keine MaxSOC Begrenzung\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## und keine Midday Steuerung\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : MaxSOC Begrenzung und Midday Steuerung im Winterbetrieb deaktiviert&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Umschaltung des MinSoc wenn viel Leistung erwartet wir, das wäre dann Frühling/Sommer\&lt;br /&gt;
##\&lt;br /&gt;
10_MinSOC_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit] and         ## sobald viel Ladung erwartet wird und der MinSoc noch\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;gt; [$SELF:SpeicherMinSOC_Sommer]    and         ## noch im Winter Modus ist\&lt;br /&gt;
        [10:09] \&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
                                                                                           \&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Sommer]);;        ## den MinSOC auf Sommerbetrieb herabsetzen, es kann\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_10 : Batterie MinSoc auf Sommerbetrieb&amp;quot;};;                              ## wieder mehr Leistung genutzt werden\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Der Speicher ist voll geladen. Hier wird das ständige nachladen auf 100 % vermieden.\&lt;br /&gt;
##\&lt;br /&gt;
11_Speicher_voll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ( [WR_ctl:Yield_fc0_day]        &amp;gt;  [$SELF:SpeicherMaxSOC_fc1_Limit] and    ## 1) sobald viel Leistung erwartet wird und der Speicher voll ist\&lt;br /&gt;
         [WR_1:Act_state_of_charge]    == 100                              and    ##    den MaxSOC wieder reduzieren, damit nicht immer nachgeladen wird\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_Actual] ne 95                                      ##   \&lt;br /&gt;
        or\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_Actual] == 95 and                                  ## 2) oder das Nachladen gestoppt wurde\&lt;br /&gt;
         [WR_1:Act_state_of_charge] &amp;lt;=  98  and                                   ##    und der SOC unte 98 % gefallen ist\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,-7200,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)}])                    ##    zwei Stunden vor Sonnenuntergang eventuell wieder nachladen\&lt;br /&gt;
       ) and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot; ) {                       ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([WR_1:Act_state_of_charge] &amp;lt;= 98) {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                         ## Eventuell noch mal nachladen\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 100 % nachladen&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;95&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                       ## Start regelmäßiges senden der Kommandos\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## MaxSOC Begrenzung weil Speicher bereits 100 % hat\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 95 % reduziert&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 WR_1_Speicher_1 DC_Power_Abs setzen z.B. zur Zwangsentladung\&lt;br /&gt;
##     dies muss manuell wiederholt werden. Danach hängt es vom WR ab, wie er die Speichersteuerung fortsetzt.\&lt;br /&gt;
12_DC_Power_Abs \&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot;                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot; ) {                        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs &amp;quot;.[$SELF:SpeicherDcPowerAbs]);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_12 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 13 WR_1_Speicher_1 Status aktualisieren.\&lt;br /&gt;
##   Dies ist momentan nur für den BYD HV Speicher, da der BYD HVS eine direkte Abfrage nicht unterstützt.\&lt;br /&gt;
##   Wer keinen BYD HV Speicher hat kann das löschen\&lt;br /&gt;
13_Status_WR_1_Speicher_1_BYD\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
      or\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot; ) {          ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 BatteryInformation&amp;quot;);;\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 StatisticInformation&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_13 : Speicher Status abfrage, BYD HV direkt&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 14_Lüfter_ein\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 15_Lüfter_aus\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 17 Wiederhole alle 180s das Kommando für die DcPowerAbs Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
17_Kommando_Wiederholung_DcPowerAbs\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [$SELF:SpeicherTriggerLaden] eq &amp;quot;An&amp;quot;  and                         ## Ist der Trigger für das Zwangsladen aktiv?\&lt;br /&gt;
       [$SELF:SpeicherDcPowerAbs]   ne 0     and                         ## Wurde eine Lade/Entlade Leistung eingestellt?\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot; ) {   ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs [$SELF:SpeicherDcPowerAbs]&amp;quot;);;\&lt;br /&gt;
   set_Exec(&amp;quot;17_Battery_EM_State&amp;quot;,30,&#039;::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;)&#039;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_17 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl alias WR_1_Speicher_1_ExternControl&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl comment Version 2023.06.21 14:00\&lt;br /&gt;
\&lt;br /&gt;
Hier können externe Trigger für die Ladung und Entladung Der Batterie gesetzt werden.\&lt;br /&gt;
Die Zeiten können z.B. durch den WeekDayTimer entsprechend an einen Stromtarif angepasst werden.\&lt;br /&gt;
Das reading SpeicherEntladung Automatik/Zeit/SpeicherTrigger ermöglicht es die Zeitsteuerung zu überschreiben.\&lt;br /&gt;
\&lt;br /&gt;
ExternTrigger\&lt;br /&gt;
Das reading dient dem Freigeben und Sperren der externen Trigger, z.B. um im Herbst/Winter das smart_laden zu steuern.\&lt;br /&gt;
Es verriegelt somit die Zeitsteuerung oder den SpeicherTrigger.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger \&lt;br /&gt;
Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API\&lt;br /&gt;
Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst\&lt;br /&gt;
SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung\&lt;br /&gt;
\&lt;br /&gt;
SpeicherTrigger:entladen,gesperrt\&lt;br /&gt;
Dieser Trigger kann durch ander Logik gesetzt werden.\&lt;br /&gt;
Auch hier wäre eine Zeitsteuerung denkbar, die entladen/gesperrt entsprechend umschaltet.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherZeitStart/SpeicherZeitEnde\&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.\&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.\&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.\&lt;br /&gt;
\&lt;br /&gt;
Speicher*ControlActive\&lt;br /&gt;
Das jeweilige reading aktiviert diese Teilkomponente für die Steuerung.\&lt;br /&gt;
Ein jeweiliges Speicher*ControlRunning signalisiert, ob gerade die Bedingungen erfüllt sind.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherCmdRepeatActive\&lt;br /&gt;
Es muss im WR die externe Speicher Steuerung aktiviert sein.\&lt;br /&gt;
Möchte man trotzdem die Sendung der ExternControl Kommandos stoppen, obwohl die Bedingungen erfüllt sind,\&lt;br /&gt;
kann man dieses reading zum Deaktivieren auf 0 setzen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMiddayControl\&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMaxSOCControl\&lt;br /&gt;
Es wird versucht den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMinSOC\&lt;br /&gt;
Dies gehört zur Basis Steuerung und schaltet den MinSOC von Sommer auf Winter Betrieb,\&lt;br /&gt;
um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl disable 0&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl readingList SpeicherExternTrigger SpeicherCmdRepeatActive SpeicherZeitStart SpeicherZeitEnde SpeicherEntladung SpeicherTrigger SpeicherMiddayControlActive SpeicherMidday_Inverter_Max_Power SpeicherMidday_MaxChargePowerAbs_morning SpeicherMidday_MaxChargePowerAbs_midday SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC SpeicherMidday_NotBefore SpeicherMinSOC_Sommer SpeicherMinSOC_Winter SpeicherMinSOC_fc1_Limit SpeicherMaxSOCControlActive SpeicherMaxSOC_Actual SpeicherMaxSOC_DayBefore SpeicherMaxSOC_fc1_Limit&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl setList SpeicherExternTrigger:frei,gesperrt SpeicherCmdRepeatActive:0,1 SpeicherZeitStart:time SpeicherZeitEnde:time SpeicherEntladung:Automatik,Zeit,Trigger SpeicherTrigger:entladen,gesperrt,none SpeicherMiddayControlActive:0,1 SpeicherMidday_Inverter_Max_Power:slider,3000,500,20000 SpeicherMidday_MaxChargePowerAbs_morning:slider,0,50,1000 SpeicherMidday_MaxChargePowerAbs_midday:slider,0,100,4700 SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC:slider,20,5,50 SpeicherMidday_NotBefore:time SpeicherMinSOC_Sommer:slider,5,1,20 SpeicherMinSOC_Winter:slider,5,1,20 SpeicherMinSOC_fc1_Limit:slider,7000,500,17000 SpeicherMaxSOCControlActive:0,1 SpeicherMaxSOC_Actual:slider,60,5,100 SpeicherMaxSOC_DayBefore:slider,15,5,100 SpeicherMaxSOC_fc1_Limit:slider,10000,2000,50000&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl sortby 122&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
#########################################################\&lt;br /&gt;
## &amp;quot;Spalte 0&amp;quot;|&amp;quot;Spalte 1&amp;quot;|&amp;quot;Spalte 2&amp;quot;|&amp;quot;Spalte 3&amp;quot;|&amp;quot;Spalte 4&amp;quot;|&amp;quot;Spalte 5&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / DcPowerAbs / Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_Speicher,smart_Laden_start,smart_Laden_beenden,smart_Laden_starten_WB_1,smart_Laden_beenden_WB_1,Kommando_Wiederholung,SOC_Calculation,Reset,DC_Power_Abs,Sommer,Winter,Speicher_voll,14_Luefter_ein,15_Luefter_aus,Status_WR_1_Speicher_1_BYD&amp;quot;) | widget([$SELF:SpeicherDcPowerAbs],&amp;quot;selectnumbers,-4500,250,4500,0,lin&amp;quot;).&amp;quot;W&amp;quot;.widget([$SELF:SpeicherTriggerLaden],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |[WR_1_API:Battery_EM_State]|([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and [WR_1_API:Battery_InternControl_MinHomeConsumption] == 30000)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;smart_Laden aktiv&amp;lt;/span&amp;gt;&#039;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Speicher&amp;lt;dd&amp;gt;Steuerung&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherEntladung],&amp;quot;uzsuDropDown,Automatik,Trigger,Zeit&amp;quot;) |&amp;quot;WB_1 Laden &amp;quot;.widget([$SELF:SpeicherWB_1_buffer],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|\&lt;br /&gt;
FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,&amp;quot;Laden&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Standby&amp;quot;,15,&amp;quot;red&amp;quot;,&amp;quot;Entladen&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_Status([WR_1:Act_state_of_charge],15,&amp;quot;red&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,49,&amp;quot;green&amp;quot;,&amp;quot;Speicher SOC&amp;quot;)|\&lt;br /&gt;
\&lt;br /&gt;
 FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],&amp;quot;orange&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],15,&amp;quot;red&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P]).&amp;quot; W&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([WR_1:Act_state_of_charge])).STY(::round([WR_1:Act_state_of_charge],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Trigger&amp;lt;dd&amp;gt;Status / ExternTrigger / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherTrigger],&amp;quot;uzsuDropDown,entladen,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherExternTrigger],&amp;quot;uzsuDropDown,frei,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherZeitStart],&amp;quot;time&amp;quot;) | widget([$SELF:SpeicherZeitEnde],&amp;quot;time&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Kommando Wiederholung&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherCmdRepeatActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherCmdRepeatRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMaxSOCControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMaxSOCControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Limit&amp;lt;dd&amp;gt;fc1_Limit / Minimum SOC Zeit / gestern / geplant&amp;lt;/dd&amp;gt;&amp;quot; |\&lt;br /&gt;
FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMaxSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;). widget([$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;) | ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot;)?(POSIX::strftime(&amp;quot;%H:%M&amp;quot;,::localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,&amp;quot;&amp;quot;)))).&amp;quot; &amp;quot;.[$SELF:SpeicherMaxSOC_MinSOC_MinSOC].&amp;quot; %&amp;quot;):&amp;quot;wartet&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_DayBefore])).STY(&amp;quot;gestern&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_DayBefore],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_Actual])).STY(&amp;quot;geplant&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_Actual],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMiddayControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMiddayControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Limits&amp;lt;dd&amp;gt;Inverter_Max_Power / Laden nicht vor / Start /Stop&amp;lt;br&amp;gt;MaxSOC morgens / Power morgens / Power mittags&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMidday_Inverter_Max_Power],&amp;quot;selectnumbers,1000,250,15000,0,lin&amp;quot;).&amp;quot;W&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:SpeicherMidday_MaxSOC],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; | widget([$SELF:SpeicherMidday_NotBefore],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_morning],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_start],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_midday],&amp;quot;selectnumbers,0,100,4700,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_stop],&amp;quot;time&amp;quot;).([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0)?&amp;quot;dynamisch&amp;quot;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MinSOC Steuerung&amp;lt;dd&amp;gt;fc1_Limit / Winter | Sommer /aktuell&amp;lt;/dd&amp;gt;&amp;quot;|\&lt;br /&gt;
 FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMinSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;).widget([$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;).&amp;quot;wh&amp;quot; |\&lt;br /&gt;
 widget([$SELF:SpeicherMinSOC_Winter],&amp;quot;selectnumbers,10,1,30,0,lin&amp;quot;).widget([$SELF:SpeicherMinSOC_Sommer],&amp;quot;selectnumbers,5,1,10,0,lin&amp;quot;).&amp;quot;%&amp;quot; |&amp;quot;&amp;quot;|[WR_1_API:Battery_InternControl_MinSoc].&amp;quot; %&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherCmdRepeatActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherCmdRepeatRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-11 17:23:40 SpeicherDcPowerAbs 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:13 SpeicherEntladung Automatik&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherExternTrigger none&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherMaxSOCControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOCControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOC_Actual 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMaxSOC_DayBefore 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_MinSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_Time NULL&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:38:43 SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:27 SpeicherMiddayControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMiddayControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:12 SpeicherMidday_Inverter_Max_Power 9000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-08 11:21:31 SpeicherMidday_MaxChargePowerAbs_midday 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:31 SpeicherMidday_MaxChargePowerAbs_morning 450&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:28 SpeicherMidday_MaxSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-03 09:21:27 SpeicherMidday_NotBefore 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 18:45:27 SpeicherMinSOC_Sommer 5&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:54 SpeicherMinSOC_Winter 20&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-15 08:04:40 SpeicherMinSOC_fc1_Limit 16000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:05 SpeicherTrigger entladen&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 16:10:24 SpeicherZeitEnde 19:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:41:25 SpeicherZeitStart 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 WB_1_smart_laden_before ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1 ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;&#039;&#039;&#039;disable 1&#039;&#039;&#039;&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_0_KSEM ModbusAttr 1 60 192.168.178.xyz:502 TCP&lt;br /&gt;
attr WR_0_KSEM DbLogExclude .*&lt;br /&gt;
attr WR_0_KSEM DbLogInclude Active_energy.*&lt;br /&gt;
attr WR_0_KSEM alias WR_0_KSEM&lt;br /&gt;
attr WR_0_KSEM comment Version 2021.04.07 12:00\&lt;br /&gt;
Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\&lt;br /&gt;
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\&lt;br /&gt;
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\&lt;br /&gt;
\&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\&lt;br /&gt;
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\&lt;br /&gt;
\&lt;br /&gt;
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
attr WR_0_KSEM dev-h-defPoll 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr WR_0_KSEM disable 0&lt;br /&gt;
attr WR_0_KSEM event-on-change-reading Active_energy.*,M_AC_Current_.*&lt;br /&gt;
attr WR_0_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr WR_0_KSEM icon measure_power&lt;br /&gt;
attr WR_0_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr WR_0_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr WR_0_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr WR_0_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40075-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr WR_0_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr WR_0_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr WR_0_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40084-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40086-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40087-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr WR_0_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr WR_0_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr WR_0_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40091-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40096-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr WR_0_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr WR_0_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr WR_0_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40101-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr WR_0_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr WR_0_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr WR_0_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr WR_0_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr WR_0_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h512-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr WR_0_KSEM obj-h512-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h516-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr WR_0_KSEM obj-h516-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr WR_0_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr WR_0_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr WR_0_KSEM obj-h8196-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr WR_0_KSEM obj-h8212-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr WR_0_KSEM obj-h8228-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr WR_0_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr WR_0_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_0_KSEM sortby 140&lt;br /&gt;
attr WR_0_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr WR_0_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===BYD HV Speicher (mit HTTPMOD)===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort wird mit KeyValue() (siehe oben) verwaltet.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Der BYD HV Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
 - Die erste Abfrage führt das Login durch&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num *&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
&lt;br /&gt;
======KeyValue() speichern======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline aufgerufen werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition WR_1_Speicher_1 (BYD HV)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1 HTTPMOD http://%IP-WR_1_Speicher_1%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr WR_1_Speicher_1 DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1 DbLogInclude BatteryInformation_TotalVoltage,BatteryInformation_SOC,BatteryInformation_SOC,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 authRetries 1&lt;br /&gt;
attr WR_1_Speicher_1 comment Version 2021.04.07 12:00&lt;br /&gt;
attr WR_1_Speicher_1 dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_Speicher_1 enableControlSet 0&lt;br /&gt;
attr WR_1_Speicher_1 enableCookies 1&lt;br /&gt;
attr WR_1_Speicher_1 event-on-change-reading auth_.*,Battery.*_.*,Device.*_.*,Installation.*_.*,Array_.*,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 event-on-update-reading Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr WR_1_Speicher_1 get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr WR_1_Speicher_1 get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr WR_1_Speicher_1 get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr WR_1_Speicher_1 get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr WR_1_Speicher_1 get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr WR_1_Speicher_1 get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr WR_1_Speicher_1 get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr WR_1_Speicher_1 get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr WR_1_Speicher_1 get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr WR_1_Speicher_1 get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr WR_1_Speicher_1 get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr WR_1_Speicher_1 get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr WR_1_Speicher_1 get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr WR_1_Speicher_1 get01-16Name Array_Main_Current&lt;br /&gt;
attr WR_1_Speicher_1 get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr WR_1_Speicher_1 get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr WR_1_Speicher_1 get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr WR_1_Speicher_1 get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr WR_1_Speicher_1 get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr WR_1_Speicher_1 get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr WR_1_Speicher_1 get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr WR_1_Speicher_1 get01-22Name Array_Main_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr WR_1_Speicher_1 get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-73Name Array_Main_Power&lt;br /&gt;
attr WR_1_Speicher_1 get01-80Name Array_Series_Battery&lt;br /&gt;
attr WR_1_Speicher_1 get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr WR_1_Speicher_1 get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get01Name RunData&lt;br /&gt;
attr WR_1_Speicher_1 get01RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get02Name StatisticInformation&lt;br /&gt;
attr WR_1_Speicher_1 get02RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get02URL http://%IP-WR_1_Speicher_1%/asp/StatisticInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr WR_1_Speicher_1 get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr WR_1_Speicher_1 get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03Name DeviceInformation&lt;br /&gt;
attr WR_1_Speicher_1 get03RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get03URL http://%IP-WR_1_Speicher_1%/asp/DeviceInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-37Name BatteryInformation_Power&lt;br /&gt;
attr WR_1_Speicher_1 get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr WR_1_Speicher_1 get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-9Name BatteryInformation_Current&lt;br /&gt;
attr WR_1_Speicher_1 get04DeleteIfUnmatched 1&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get04Name BatteryInformation&lt;br /&gt;
attr WR_1_Speicher_1 get04RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr WR_1_Speicher_1 get04URL http://%IP-WR_1_Speicher_1%/asp/Home.asp&lt;br /&gt;
attr WR_1_Speicher_1 get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr WR_1_Speicher_1 get05Name InstallationConfig&lt;br /&gt;
attr WR_1_Speicher_1 get05RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get05URL http://%IP-WR_1_Speicher_1%/asp/UserInfo.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Data ArrayNum=1&amp;amp;SeriesBatteryNum=4&lt;br /&gt;
attr WR_1_Speicher_1 get10Header01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 get10Header02 Referer: http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Header03 Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
attr WR_1_Speicher_1 get10Header04 Accept: text/html,application/xhtml+xml,application/xml&lt;br /&gt;
attr WR_1_Speicher_1 get10Name Test_Array&lt;br /&gt;
attr WR_1_Speicher_1 get10URL http://%IP-WR_1_Speicher_1%/goform/SetRunData&lt;br /&gt;
attr WR_1_Speicher_1 getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1 handleRedirects 1&lt;br /&gt;
attr WR_1_Speicher_1 httpVersion 1.1&lt;br /&gt;
attr WR_1_Speicher_1 icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1 reAuthRegex Unauthorized&lt;br /&gt;
attr WR_1_Speicher_1 reading01Name auth_qop&lt;br /&gt;
attr WR_1_Speicher_1 reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Name auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Name auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Name auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Regex %IP-WR_1_Speicher_1%&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Value ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1_Speicher_1&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Regex %auth_realm%&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Value auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Regex %auth_nonce%&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Value auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Regex %auth_opaque%&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Value auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Regex %auth_response%&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Value {my $NAME=&amp;quot;WR_1_Speicher_1&amp;quot;;;my $pw=KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;);; $pw =~ &#039;&amp;quot;&#039;.s/@/\\@/g.&#039;&amp;quot;&#039;;; md5_hex(md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.$pw).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:00000001:d789ea5b7e9a2377:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;));;}&lt;br /&gt;
attr WR_1_Speicher_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1 showBody 0&lt;br /&gt;
attr WR_1_Speicher_1 showError 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid01ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sid02Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid02ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid02URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sortby 121&lt;br /&gt;
attr WR_1_Speicher_1 stateFormat {sprintf(&amp;quot;Total_Charge_Energy: %.0f kWh&amp;lt;br&amp;gt;Total_Efficiency: %.1f %% Battery_EM_State: %s&amp;quot;, ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Efficiency&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;Battery_EM_State&amp;quot;,&amp;quot;&amp;quot;))}&lt;br /&gt;
attr WR_1_Speicher_1 userReadings Statistic_SpecificInformation_00_Date:Statistic_SpecificInformation_05_EndTime.* { CommandDeleteReading(undef, $NAME.&amp;quot; .*-.*&amp;quot;);;;; localtime()},\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Difference_Charge_Energy:Statistic_GeneralInformation_Total_Charge_Energy.*  {ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Efficiency:Statistic_GeneralInformation_Total_Charge_Energy.*  {round(((ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)+((ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Act_state_of_charge&amp;quot;,0)/100)*11)) / ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0))*100 , 2)}&lt;br /&gt;
attr WR_1_Speicher_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1                    BYD HV     HTTPMOD   LAN/WLAN               Speicher Details, auch über einzelne Zellen. Das kann man nur für den alten BYD HV verwenden.&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Verwendet von Plenticore zur Steuerung des Speichers&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
PV_Schedule                                   DOIF                             Startet regelmäßige Aktionen&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Das ist veraltet, da die KI_Prognose nun verwendet werden sollte.&lt;br /&gt;
   2 Stündlich von 07:00 bis 20:00&lt;br /&gt;
   2.1 WR_1_config module_1_covered                                              Schnee auf den Modulen (noch in der Entwicklungsphase)&lt;br /&gt;
   2.2 Solar_forecast() für fc0                                                  Aktualisieren der fc0 Prognose&lt;br /&gt;
&lt;br /&gt;
   3 zweimal am Tag&lt;br /&gt;
   3.1 Solar_forecast() für fc1                                                  Aktualisieren der fc1 Prognose&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
   4 alle 5 Minuten&lt;br /&gt;
   4.1 WR_2_API 04_auth_me                                                       Aktualisieren der Bilanz (es wird ein Event erzeugt)&lt;br /&gt;
   4.2 WR_1_API 04_auth_me                                                       Der Master Wechselrichter kommt zum Schluss, damit die SW_* readings auch von anderen&lt;br /&gt;
                                                                                 Wechselrichtern die richtigen Werte haben.&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
Dies ist jetzt im WR_ctl Device enthalten&lt;br /&gt;
WR_*_config                                   DUMMY                            Konfiguration für Strings,Ausrichtung,Nennleistung,IP-Adressen,Forecast&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC               begrenzt dann morgens den MaxSOC&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday     und den MaxChargePowerAbs&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning    für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_1:Solar_middayhigh_fc0_start &amp;lt;&amp;gt; WR_1:Solar_middayhigh_fc0_stop      Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_1:Solar_middayhigh_fc0_stop                         Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====SVG====&lt;br /&gt;
In eventuellen SVGs die Device und reading Namen korrigieren&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== AW Definition PV_Schedule (DOIF)===&lt;br /&gt;
Aufgrund der Komplexität wurde die Speichersteuerung aus diesem Device entfernt und im Device PV_1_Speicher_1_ExternControl ausgelagert.&lt;br /&gt;
Weitere Neuerungen sind die Bereitstellung eines Schnee Faktors pro String für die Solar_forecast() Funktion, was aber bitte als Versuch anzusehen ist.&lt;br /&gt;
Für den Vergleich mit dem Solar_Foracast Modul wird der Forecast zwei mal aufgerufen und einmal davon ins DWD_Forecast_Test geschrieben.&lt;br /&gt;
Diese Beispiele können natürlich einfach herausgelöscht werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
\&lt;br /&gt;
   (get WR_2_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
   (get WR_1_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 5 und 21 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([05:00-21:00] and [:00])\&lt;br /&gt;
   ## Erste Versuche mit Schnee, wenn zuwenig Strom in den Modulen fließt wird ein Faktor von 0.1 gesetzt\&lt;br /&gt;
   ## WR_1_config forecast_factor_autocorrection muss auf 1 gesetzt sein, damit das berücksichtigt wird\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt;  8 &amp;amp;&amp;amp; $hour &amp;lt; 12)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_1_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_2_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 12 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_3_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_4_covered &amp;quot;.$y)})\&lt;br /&gt;
\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   ## Bei Schnee wurde der module_*_covered Faktor bereits am Vortag gesetzt.\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 regelmäßig die Bilanz aktualisieren, alle 5 Minuten außer um :00\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00])\&lt;br /&gt;
\&lt;br /&gt;
  (get WR_2_API 04_auth_me)\&lt;br /&gt;
  (get WR_1_API 04_auth_me)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])   ## 6172\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])         ## 4727\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5707\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 4717\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5241\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 3517\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState WR Status|Forecast 0|Forecast 1|Bilanz refresh&lt;br /&gt;
attr PV_Schedule comment Version 2021.04.19 12:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0,3:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4&lt;br /&gt;
attr PV_Schedule webCmdLabel Statistic :Forecast_0 :Forecast_1 :Bilanz :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc.*_.*_Rad1h,fc.*_.*_TTT,fc.*_.*_FF,fc.*_.*_Neff,fc.*_.*_R101,fc.*_.*_RRS1c,fc.*_.*_DD,fc.*_.*_N,fc.*_.*_VV,fc.*_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2022.08.20 12:00\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
FF      : Windspeed\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc.*_.*_[Rad1h|TTT|FF|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,FF,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz,fc.*_.*&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro event-on-update-reading ObsDate.*,fc.*_.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
attr Astro userReadings fc0_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
\&lt;br /&gt;
fc1_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))}&lt;br /&gt;
attr Astro verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
CREATE DEFINER=`fhemuser`@`%` PROCEDURE `dwd_load`(IN var_date DATE, IN display char(10))&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;br /&gt;
SET @date:= var_date;&lt;br /&gt;
-- die alte Tabelle löschen&lt;br /&gt;
DROP TABLE IF EXISTS dwdfull;&lt;br /&gt;
&lt;br /&gt;
-- eine neue Tabelle anlegen&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `dwdfull` (&lt;br /&gt;
  `TIMESTAMP` datetime NOT NULL,&lt;br /&gt;
  `year`   int NOT NULL,&lt;br /&gt;
  `month`  int NOT NULL,&lt;br /&gt;
  `day`    int NOT NULL,&lt;br /&gt;
  `hour`   int NOT NULL,&lt;br /&gt;
  `TTT`    float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `DD`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `VV`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `N`      float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Neff`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `R101`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `RRS1c`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunD1`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Rad1h`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAz`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAlt` float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `yield`  float  DEFAULT 0,&lt;br /&gt;
  `yield_max`  float  DEFAULT 0,&lt;br /&gt;
  `forecast`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  PRIMARY KEY (`TIMESTAMP`),&lt;br /&gt;
  INDEX (`TIMESTAMP`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=&#039;DWD Forecast&#039;;&lt;br /&gt;
&lt;br /&gt;
-- als erstes die Grundlegenden Daten mit Zeitstempeln erzeugen&lt;br /&gt;
-- Rad1h wird als erstes eingetragen&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc0 Rad1h ältere Werte eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
	 	       )&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc1 Rad1h Werte von morgen eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Mit update alle weiteren Spalten füllen&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAz&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t2  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t2.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAz&lt;br /&gt;
  SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAlt&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t6 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t6.VV&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t5.VV&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t7 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t7.DD&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t5.DD&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t8 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t8.TTT&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t5.TTT&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t9 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t9.R101&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t5.R101&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t10 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t10.N&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t5.N&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t11 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t11.RRS1c&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t5.RRS1c&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield from Plenticore with Accu&lt;br /&gt;
   -- start left join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    left JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end left join&lt;br /&gt;
   &lt;br /&gt;
   UNION  -- for left and right join&lt;br /&gt;
&lt;br /&gt;
   -- start right join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    right JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end right join&lt;br /&gt;
   &lt;br /&gt;
   -- UNION end&lt;br /&gt;
   &lt;br /&gt;
  ) t12 USING(TIMESTAMP)&lt;br /&gt;
SET tt.yield = t12.yield&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Ermittle Ertrags Maximum der letzten 30 Tage um die Prognose zu limitieren&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield_max&lt;br /&gt;
      SELECT hour,&lt;br /&gt;
             cast(max(yield) AS DECIMAL(6)) AS yield_max&lt;br /&gt;
      FROM dwdfull&lt;br /&gt;
      WHERE TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
      GROUP BY hour&lt;br /&gt;
   ) t2  USING(hour)&lt;br /&gt;
SET tt.yield_max = t2.yield_max&lt;br /&gt;
WHERE TIMESTAMP &amp;gt; @date&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
IF display = &#039;show&#039; THEN &lt;br /&gt;
  select * from dwdfull LIMIT 3000;&lt;br /&gt;
ELSE&lt;br /&gt;
  select now();&lt;br /&gt;
END IF&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose (nicht mehr aktuell)==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
====Wetter Forecast Grundlagen (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der &lt;br /&gt;
    Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deutscher Wetter Dienst (DWD) (nicht mehr aktuell)===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
====RAW Definition DWD_Forecast (nicht mehr aktuell)====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wurden einige extra Werte vom DWD abgefragt, die für das Solar_Forecast Modul verwendet werden. Dieses Modul ist noch in der experimental Phase (2021.02.23) und liefert noch nicht gleichwertige Ergebnisse. Ein Test zum vergleichen kann aber nicht schaden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc0_.*_Rad1h,fc0_.*_TTT,fc0_.*_Neff,fc0_.*_R101,fc0_.*_RRS1c,fc0_.*_DD,fc0_.*_N,fc0_.*_VV,fc0_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2023.01.05 12:40\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc0_.*_[Rad1h|TTT|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===99_myUtils.pm Funktionen===&lt;br /&gt;
====Solar_forecast() (nicht mehr aktuell)====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen, muss ein Dummy WR_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Letzte Neuerungen:&lt;br /&gt;
- IM WR_1_config kann man verbose auf &amp;gt;3 setzen und bekommt dann Log Meldungen&lt;br /&gt;
- Es wird eine Autokorrektur unterstützt. Aktivierung durch &amp;quot;setreading WR_1_config forecast_factor_autocorrection 1&amp;quot;&lt;br /&gt;
  Für die Datenbank Anbindung wird ein DbRep Device LogDBRep_PV_Forecast_SQL verwendet. Die RAW definition kommt gleich im Anschluss.&lt;br /&gt;
- Das SQL für die Berechnung des Faktors der Autokorrektur Verwendet Konfigurationsvariablen aus den DbRep Device.&lt;br /&gt;
- Bei der Autokorrektur wird auch eine Bedeckung von Schnee (Strom im String &amp;lt; 1A) berücksichtigt. (das ist noch in der Entwicklung)&lt;br /&gt;
  Dieser Faktor wird im PV_Schedule Device erzeugt und dann im &amp;quot;WR_1_config module_*_covered&amp;quot; für jeden String eingetragen.&lt;br /&gt;
  Das muss jeder individuell für seine Anlage anpassen!&lt;br /&gt;
- Für die 70% Regelung wird nun auch ein Middayhigh Trigger ermittelt und die jeweilige Start/Stop Zeit. Dies steht dann im WR_1 Device bei den Solar_* readings&lt;br /&gt;
- Es besteht auch die Möglichkeit die Solar_forecast() Funktion ohne Datenbank zu verwenden, dann ist bei den Parametern &amp;quot;none&amp;quot; zu übergeben und&lt;br /&gt;
  es muss auch die Autokorrektur abgeschaltet sein.&lt;br /&gt;
- Anstelle des Wechselrichter Devices kann nun auch ein beliebiges anderes Device angegeben werden, in das dann der Forecast geschrieben wird.&lt;br /&gt;
  Auch hier kann dann keine Autokorrektur verwendet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.06.14 15:20&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;        # Mit dieser Datenbank wird gearbeitet&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zur Kommunikation mit der LogDB verwendet und muss entsprechend konfiguriert sein&lt;br /&gt;
     my $logdevice   = &amp;quot; &amp;quot;   ;        # Das ist der Wechselrichter, oder ein anderes Device, in das die Prognose geschrieben wird&lt;br /&gt;
        $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;    # Der reading Name wird um 0 oder 1 verlängert&lt;br /&gt;
&lt;br /&gt;
     # Welcher Verbose Level ist gesetzt?&lt;br /&gt;
     my $verbose = AttrVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Gibt es einen festen Korrekturfaktor für jede Stunde?&lt;br /&gt;
     my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
     # Soll eine Autokorrektur gemacht werden? 0 = Nein 1 = Ja&lt;br /&gt;
     my $autocorrection          = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor_autocorrection&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Beim DWD wird der Wert für die Stunde erst am Ende der Stunde eingetragen&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     # Hier werden die Variablen vorbelegt&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry1h,$logentry4h,$logentryrest,$logentry,$i) = (0) x 9 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($module_covered,$Solar_Correction_Faktor_auto,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 6 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 06:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $logdbrep ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
       # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
       CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Setzen der Tageszähler und Merker&lt;br /&gt;
     $logentry            = 0 ;   # Summiert den Solar_Calculation Wert für den ganzen Tag&lt;br /&gt;
     $logentry4h          = 0 ;   # Summierung für die nächsten vier Stunden&lt;br /&gt;
     $logentryrest        = 0 ;   # Summierung für den Rest des Tages&lt;br /&gt;
&lt;br /&gt;
     my $middayhigh           = 0 ; # Ein Merker, ob das Tagesmaximum überschritten wird&lt;br /&gt;
     my $middayhigh_start     = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_stop      = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_tmp       = 0;&lt;br /&gt;
     my $middayhigh_start_tmp = 0;&lt;br /&gt;
     my $middayhigh_stop_tmp  = 0;&lt;br /&gt;
&lt;br /&gt;
     my $Inverter_Max_Power = ReadingsVal($logdevice.&amp;quot;_Speicher_1_ExternControl&amp;quot;,&amp;quot;SpeicherMidday_Inverter_Max_Power&amp;quot;,&amp;quot;unused&amp;quot;);  # Überschreiben des middayhigh&lt;br /&gt;
     if ($Inverter_Max_Power eq &amp;quot;unused&amp;quot;) {&lt;br /&gt;
       $Inverter_Max_Power = ReadingsVal($logdevice,&amp;quot;Inverter_Max_Power&amp;quot;,0) +500 ;      # Hier wird ein Durchschnittsverbrauch des Hauses aufaddiert&lt;br /&gt;
     } else {&lt;br /&gt;
       if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power manuell gesetzt&amp;quot; } ;&lt;br /&gt;
     };&lt;br /&gt;
     if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power auf &amp;quot;.$Inverter_Max_Power.&amp;quot; gesetzt&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
     # Es werden Stundenwerte von 06:00 bis 21:00 Uhr berechnet&lt;br /&gt;
     for ($i = 6; $i &amp;lt;= 21; $i++) {&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0 and $i == 6) {&lt;br /&gt;
         # Neuberechnung der stündlichen Autokorrektur Faktoren in der Datenbank. Das DbRep Device LogDBRep_PV_Forecast_SQL muss vorhanden sein.&lt;br /&gt;
         # Achtung, beim SQL muss &#039;@&#039; mit &#039;\@&#039; maskiert werden.&lt;br /&gt;
         CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking &amp;quot;.sprintf(&amp;quot;&lt;br /&gt;
               INSERT INTO history&lt;br /&gt;
                 (TIMESTAMP,DEVICE,READING,VALUE)&lt;br /&gt;
                  SELECT&lt;br /&gt;
                    TIMESTAMP,DEVICE,READING,VALUE&lt;br /&gt;
                  FROM (&lt;br /&gt;
                    SELECT&lt;br /&gt;
                      DATE_ADD(CURDATE(),INTERVAL t2.HOUR HOUR) AS TIMESTAMP,&lt;br /&gt;
                      t2.DEVICE,&lt;br /&gt;
                      \@readingname                             AS READING,&lt;br /&gt;
                      cast(if(avg(t2.FACTOR) &amp;gt; 1.6, 1.6,&lt;br /&gt;
                              avg(t2.FACTOR) ) AS DECIMAL(2,1)) AS VALUE&lt;br /&gt;
                    FROM (&lt;br /&gt;
                      SELECT * FROM (&lt;br /&gt;
                        SELECT&lt;br /&gt;
                          t1.TIMESTAMP,&lt;br /&gt;
                          t1.HOUR,&lt;br /&gt;
                          t1.DEVICE,&lt;br /&gt;
                          t1.READING,&lt;br /&gt;
                          t1.VALUE,&lt;br /&gt;
                          if(\@diff = 0,0, \@temp:=cast((t1.VALUE-\@diff) AS DECIMAL(8,2)))                                    AS DIFF,&lt;br /&gt;
                          if(((t1.VALUE+(-1*\@temp))*\@corr)=0,0, cast((t1.VALUE/(t1.VALUE+(-1*\@temp))*\@corr) AS DECIMAL(8,1))) AS FACTOR,&lt;br /&gt;
                          \@diff:=t1.VALUE                                                                                        AS curr_V&lt;br /&gt;
                        FROM (&lt;br /&gt;
                          SELECT&lt;br /&gt;
                            h.TIMESTAMP,&lt;br /&gt;
                            date(h.TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(h.TIMESTAMP) AS HOUR,&lt;br /&gt;
                            h.DEVICE,&lt;br /&gt;
                            h.READING,&lt;br /&gt;
                            h.VALUE&lt;br /&gt;
                          FROM history AS h&lt;br /&gt;
                          WHERE h.DEVICE    =  \@device&lt;br /&gt;
                            AND (h.READING  =  \@reading1 OR h.READING = \@reading2)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;gt;= DATE_SUB(DATE(now()),INTERVAL \@days DAY)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;lt;= CURDATE()&lt;br /&gt;
                            AND MINUTE(h.TIMESTAMP) = 0&lt;br /&gt;
                            AND h.VALUE &amp;gt;= 50&lt;br /&gt;
                          GROUP BY DATE,HOUR,h.READING,h.DEVICE,h.TIMESTAMP&lt;br /&gt;
                         )t1&lt;br /&gt;
                       )tx&lt;br /&gt;
                        WHERE READING != \@reading2&lt;br /&gt;
                          AND HOUR &amp;gt; 6&lt;br /&gt;
                     )t2&lt;br /&gt;
                      GROUP BY t2.HOUR,t2.DEVICE&lt;br /&gt;
                   )t3&lt;br /&gt;
                    WHERE&lt;br /&gt;
                      t3.VALUE != 0&lt;br /&gt;
                    ORDER BY TIMESTAMP&lt;br /&gt;
                    ON DUPLICATE KEY UPDATE&lt;br /&gt;
                      VALUE=t3.VALUE;&lt;br /&gt;
           &amp;quot;) # Ende sprintf()&lt;br /&gt;
         );   # Ende CommandGet()&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
       $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
       if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
         $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
&lt;br /&gt;
         $Solar_Rain = 0;&lt;br /&gt;
         for (my $r600 = $i+5; $r600 &amp;gt;= $i; $r600--) {&lt;br /&gt;
           $Solar_Rain        += ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($r600+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
         $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
         $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
         $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
         if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation.&amp;quot; W &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0).&amp;quot; J&amp;quot; } ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($cloudk ne 0) {&lt;br /&gt;
         $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
         $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($raink ne 0) {&lt;br /&gt;
         $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($tempk ne 0) {&lt;br /&gt;
         $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0) {&lt;br /&gt;
         $Solar_Correction_Faktor_auto = CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking SELECT VALUE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;Solar_Correction_Faktor_auto&#039; AND TIMESTAMP=&#039;&amp;quot;.sprintf(&amp;quot;%4d-%02d-%02d %02d:00:00&amp;quot;,$year,$mon,$mday,$i).&amp;quot;&#039;;&amp;quot;) ;&lt;br /&gt;
         if($Solar_Correction_Faktor_auto eq &amp;quot;&amp;quot;) { $Solar_Correction_Faktor_auto = 1; };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $logentry1h = 0 ;   # Summierung für eine Stunde zurücksetzen&lt;br /&gt;
&lt;br /&gt;
       # Es werden 5 Modul Ausrichtungen durchlaufen, der Name der Ausrichtung befindet sich z.B. in WR_1_config&lt;br /&gt;
       for(my $j=1;$j&amp;lt;=5;$j++){&lt;br /&gt;
         # lesen der Modul Anzahl&lt;br /&gt;
         $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
         if ($module_count[$j] ne 0) {&lt;br /&gt;
           # Für diese Ausrichtung sind Module Installiert&lt;br /&gt;
&lt;br /&gt;
           # Berechnung des Korrekturfaktors für die Modul Ausrichtung&lt;br /&gt;
           $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;factor/plain/direction       : &amp;quot;.$Solar_Plain.&amp;quot; &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) };&lt;br /&gt;
           # Berechnung der Modul Nennleistung für diese Ausrichtung&lt;br /&gt;
           $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
           # Anwendung der Korrekturfaktoren&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp   * $Solar_Correction_Cloud * $Solar_Correction_Rain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Faktor ;&lt;br /&gt;
&lt;br /&gt;
           if ($autocorrection ne 0) {&lt;br /&gt;
             # Nachsehen, ob dieser String mit Schnee bedeckt ist&lt;br /&gt;
             $module_covered = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_covered&amp;quot;,1) ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $Solar_Correction_Faktor_auto ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $module_covered ;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot;_covered             : &amp;quot;.$module_covered };&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Runden auf volle Watt Werte&lt;br /&gt;
           $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot; estimation          : &amp;quot;.$Solar_[$j] };&lt;br /&gt;
&lt;br /&gt;
           # Aufsummieren aller konfigurierter Ausrichtungen&lt;br /&gt;
           $logentry1h += $Solar_[$j] ; # Summe für eine Stunde (wird mit jedem lauf von $i wieder auf 0 gesetzt)&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe der nächsten 4 h gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour and $i &amp;lt;= $hour+3) {&lt;br /&gt;
             $logentry4h += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe für den Resttag gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour) {&lt;br /&gt;
             $logentryrest += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           $logentry += $Solar_[$j] ; # Summe für den ganzen Tag&lt;br /&gt;
&lt;br /&gt;
           # Den Forecast Wert für die aktuelle Stunde in das Wechselrichter Device schreiben&lt;br /&gt;
           if ($fc == 0 and $hour == $i) {&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;                   : &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; };&lt;br /&gt;
             CommandSetReading(undef, $logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j]) ;&lt;br /&gt;
           };&lt;br /&gt;
         };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Alle Forecast Werte für die jeweilige Stunde in die DbLog schreiben (Es wird der Cache verwendet)&lt;br /&gt;
&lt;br /&gt;
       if ( $logdb ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
         CommandSet(undef, $logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry1h.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry1h.&amp;quot;|&amp;quot;) ;&lt;br /&gt;
&lt;br /&gt;
         if ( $middayhigh == 0 and $logentry1h &amp;gt; $Inverter_Max_Power ) {&lt;br /&gt;
           $middayhigh           = 1;&lt;br /&gt;
           $middayhigh_start_tmp = $i-1;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;lt; $Inverter_Max_Power and $middayhigh_stop_tmp == 0 )  {&lt;br /&gt;
           $middayhigh_stop_tmp = $i;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;gt; $Inverter_Max_Power and $middayhigh_stop ne &amp;quot;00:00&amp;quot; )  {&lt;br /&gt;
           $middayhigh_stop_tmp = 0;                                # da war ein kurzer Einbruch, es sollte noch länger sein.&lt;br /&gt;
         };&lt;br /&gt;
         if ($middayhigh == 1 and&lt;br /&gt;
             $middayhigh_stop_tmp != 0 and&lt;br /&gt;
             $middayhigh_stop_tmp == $i ) {                                    # das Ende des Middayhigh wurde gefunden&lt;br /&gt;
&lt;br /&gt;
           $middayhigh_tmp = $middayhigh_stop_tmp - $middayhigh_start_tmp;&lt;br /&gt;
           if ( $middayhigh_tmp &amp;gt; 4 )  {                                       # das Middayhigh wird zu lang&lt;br /&gt;
             if ($verbose &amp;gt;= 3 ) {                                             # die bisherigen Zeiten ausgeben&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp) ;&lt;br /&gt;
             }&lt;br /&gt;
             $middayhigh_tmp       = round(($middayhigh_tmp/4)-0.2 ,0);        # die Rundung der Zeit zum Abziehen etwas verschieben&lt;br /&gt;
             $middayhigh_start_tmp = $middayhigh_start_tmp + $middayhigh_tmp;  # es wird um ganze Stunden verkürzt&lt;br /&gt;
             $middayhigh_stop_tmp  = $middayhigh_stop_tmp  - $middayhigh_tmp;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) {                                              # melde die Verkürzung&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;         : verkürzt um &amp;quot;.($middayhigh_tmp *2).&amp;quot; Stunden&amp;quot;;&lt;br /&gt;
             }&lt;br /&gt;
           };&lt;br /&gt;
           $middayhigh_start = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
           $middayhigh_stop  = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp);&lt;br /&gt;
           if ($verbose &amp;gt;= 3) {                                                # gib die finalen Zeiten aus&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.$middayhigh_start;&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.$middayhigh_stop ;&lt;br /&gt;
           }&lt;br /&gt;
         };&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ; # setz die Zeiten im Device&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Sobald mindestens ein String configuriert ist sollen diese Werte, der aktuellen Stunde, in das Wechselrichter Device geschrieben werden&lt;br /&gt;
       if ($fc == 0 and $hour == $i and $module_count[1] ne 0) {&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry1h) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Auch die Solar_Calculation jeder einzelnen Stunde wird als reading in das Wechselrichter Device geschrieben&lt;br /&gt;
       CommandSetReading(undef, sprintf(&amp;quot;%s %s_%02d %d&amp;quot;,$logdevice,$reading,$i,$logentry1h)) ;&lt;br /&gt;
&lt;br /&gt;
       # Für die Fehlersuche kommen noch einige Informationen ins Log&lt;br /&gt;
       if ($verbose &amp;gt;= 3) {&lt;br /&gt;
         Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Cloud                  : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;cloudk                       : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Cloud       : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Rain                   : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;raink                        : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Rain        : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Temp                   : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;tempk                        : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Temp        : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor      : &amp;quot;.$Solar_Correction_Faktor ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor_auto : &amp;quot;.$Solar_Correction_Faktor_auto ;&lt;br /&gt;
         Log 3, &amp;quot;Forecast,Hour,Estimation 1h  : &amp;quot;.$fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$logentry1h ;&lt;br /&gt;
       };&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Die Summe der nächsten 4 Stunden in das Wechselrichter Device schreiben&lt;br /&gt;
     if ($fc == 0) {&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_4h &amp;quot;.$logentry4h) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_rest &amp;quot;.$logentryrest) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_day &amp;quot;.$logentry) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $middayhigh == 0 ) {    # Auf Defaults zurücksetzen&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.02.28 17:00&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    my $verbose     = AttrVal(&amp;quot;Astro&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = CommandGet(undef, &amp;quot;Astro text SunAz &amp;quot;.$time) ;&lt;br /&gt;
    my $elevation   = CommandGet(undef, &amp;quot;Astro text SunAlt &amp;quot;.$time) ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain time             : &amp;quot;.$time;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain azimuth          : &amp;quot;.$azimuth;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain elevation        : &amp;quot;.$elevation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain orientation      : &amp;quot;.$orientation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain angle            : &amp;quot;.$angle;&lt;br /&gt;
    };&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.1798) {&lt;br /&gt;
      if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_Forecast_SQL (nicht mehr aktuell)====&lt;br /&gt;
Dieses Device war vormals das LogDBRep_PV_Forecast_SQL , es wird jedoch nun mehrfach verwendet und wurde deshalb umbenannt. Das LogDBRep_PV_Forecast_SQL kann gelöscht werden.&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
Für die Solar_forecast() Funktion wurden hier SQL Variablen Definiert, die für die Autokorrektur verwendet werden:&lt;br /&gt;
- @days ist die Anzahl der Tage, über die ein stündlicher, durchschnitts Korrektur Faktor berechnet wird.&lt;br /&gt;
- @corr ermöglicht es diesen Faktor nochmals zu verändern &amp;lt;1 dämpft, &amp;gt;1 verstärkt&lt;br /&gt;
- @device ist der Plenticore Wechselrichter&lt;br /&gt;
- @reading1 ist die reale DC Leistung ohne die Batterie, hier wird &#039;&#039;&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;&#039;&#039; für die Schwarm Implementierung verwendet.&lt;br /&gt;
- @reading2 wird der Basisname der readings im WR_1 Device&lt;br /&gt;
- @readingname wird der reading Name des Korrekturfaktors.&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
Durch die Erweiterung zum Schwarm mit mehreren AC-Quellen wurde die Variable @reading1 verändert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_Forecast_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL allowDeletion 1&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL room System&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdVars SET @days:=3, @corr:=0.7, @diff:=0, @temp:=0, @device:=&#039;WR_1&#039;, @reading1:=&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;, @reading2:=&#039;Solar_Calculation_fc0&#039;, @readingname:=&#039;Solar_Correction_Faktor_auto&#039; ;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solar Forcast Tests (nicht mehr aktuell)===&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Astro Device Test====&lt;br /&gt;
Bei diesem Test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() Test (nicht mehr aktuell)====&lt;br /&gt;
Diese Funktion kann man folgendermaßen testen. Für Log Meldungen muss man im &#039;&#039;&#039;Astro Device verbose auf 3&#039;&#039;&#039; oder größer stellen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung, das Dach hätte demnach also Süd/West Lage.&lt;br /&gt;
&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann Folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:51:27.312 3: Solar_plain azimuth          : 210.6&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain elevation        : 0.49916224518291&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain orientation      : 0.185004188774085&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain angle            : 0.785395141022061&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain factor           : 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurückgeliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_forecast() Test (nicht mehr aktuell)====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
Bei gesetztem &amp;quot;&#039;&#039;&#039;attr Astro verbose 3&#039;&#039;&#039;&amp;quot; erscheinen hier ebenfalls die Astro Log Informationen.&lt;br /&gt;
Durch setzen von &amp;quot;&#039;&#039;&#039;attr WR_1_config verbose 3&#039;&#039;&#039;&amp;quot; bekommt man die Log Meldungen vom Sorar_forecast()&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&lt;br /&gt;
generische Verwendung ohne DbLog/DbRep: &#039;&#039;&#039;Das Astro Device muss &amp;quot;Astro&amp;quot; heißen und das DWD Device muss &amp;quot;DWD_Forecast&amp;quot; heißen!!&#039;&#039;&#039;&lt;br /&gt;
{Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;&amp;lt;beliebiges Device&amp;gt;&amp;quot;,&amp;quot;&amp;lt;prefix für die readings&amp;gt;_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,[0|1])}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann solche Blöcke, die man zusammenhängend betrachten sollte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power manuell gesetzt&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power auf 7000 gesetzt&lt;br /&gt;
2021.04.07 15:57:23.932 3: Solar_SolarRadiation         : 17 W 60.00 J        &amp;lt;&amp;lt;&amp;lt; vom DWD gelieferte Prognose in Watt und Joul&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain azimuth          : 80.2                &amp;lt;&amp;lt;&amp;lt; Astro Informationen&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain orientation      : -0.171041608489249&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain factor           : 0.001               &amp;lt;&amp;lt;&amp;lt; Die Funktion ist noch außerhalb des Gültigkeitsbereiches&lt;br /&gt;
2021.04.07 15:57:23.977 3: factor/plain/direction       : 0.001 40/-90     &lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1_covered             : 1                   &amp;lt;&amp;lt;&amp;lt; Ein Faktor für die Schneebedeckung&lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1 estimation          : 0                   &amp;lt;&amp;lt;&amp;lt; Die erwartete Leistung liegt bei 0 Watt&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:23.991 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2_covered             : 1&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain orientation      : -1.94183189053337&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.002 3: factor/plain/direction       : 0.001 40/0&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.013 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.020 3: Solar_SolarRadiation         : 17                  &amp;lt;&amp;lt;&amp;lt; Rad1h ist 70 Watt&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Cloud                  : 70                  &amp;lt;&amp;lt;&amp;lt; 70 % Abdeckung des Himmels durch Wolken&lt;br /&gt;
2021.04.07 15:57:24.021 3: cloudk                       : -0.45 0             &amp;lt;&amp;lt;&amp;lt; Werte der Korrekturfunktion für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Correction_Cloud       : 0.685               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Rain                   : 152&lt;br /&gt;
2021.04.07 15:57:24.022 3: raink                        : -0.2 0&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Correction_Rain        : 0.696               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Regen&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Temp                   : 10.7                &amp;lt;&amp;lt;&amp;lt; Erwartete Temperatur an den Modulen (Schätzung) &lt;br /&gt;
2021.04.07 15:57:24.023 3: tempk                        : -0.39 25&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Temp        : 1.056               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für die Modultemperatur&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor      : 1                   &amp;lt;&amp;lt;&amp;lt; Fester Korrekturfaktor aus WR_1_config &lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor_auto : 0.5                 &amp;lt;&amp;lt;&amp;lt; Korrekturfaktor aus der Datenbank Berechnung der letzten Tage &lt;br /&gt;
2021.04.07 15:57:24.024 3: Forecast,Hour,Estimation 1h  : 0 7 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Forecast Basiseinstellung (nicht mehr aktuell)===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät WR_1_config von einer Ost/Süd/West Anlage mitgeliefert (setstate). Es werden bis zu 5 Strings unterstützt.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auch &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät WR_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch zusätzliche Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Berücksichtigung von Temperatur, Bewölkung und Regen (nicht mehr aktuell)===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das Ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
Durch die Autokorrektur ist nun auch ein Schnee Faktor dazu gekommen. Dieser wird im PV_Schedule Device &amp;quot;berechnet&amp;quot; :-) und und in das PV_1_config geschrieben. Bei aktivierter Autokorrektur wird dieser dann berücksichtigt.&lt;br /&gt;
=====Temperatur (nicht mehr aktuell)=====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Wolken und Regen (nicht mehr aktuell)=====&lt;br /&gt;
Aus den DWD_Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken Einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
===wunderground===&lt;br /&gt;
Dieser Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das kann dann als aktueller Wert in den Diagrammen angezeigt werden und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mit einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
&lt;br /&gt;
===RAW Definition Wetter_&amp;lt;Wohnort&amp;gt;===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;JSON&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;builtIn&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;datasource&amp;quot;: &amp;quot;-- Grafana --&amp;quot;,&lt;br /&gt;
        &amp;quot;enable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;iconColor&amp;quot;: &amp;quot;rgba(0, 211, 255, 1)&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Annotations &amp;amp; Alerts&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;dashboard&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;editable&amp;quot;: true,&lt;br /&gt;
  &amp;quot;gnetId&amp;quot;: null,&lt;br /&gt;
  &amp;quot;graphTooltip&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;id&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;links&amp;quot;: [],&lt;br /&gt;
  &amp;quot;panels&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P value&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;: &amp;quot;rgb(90, 90, 90)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid value&amp;quot;: &amp;quot;rgb(250, 250, 250)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_AC_Active_P&amp;quot;: &amp;quot;dark-orange&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P&amp;quot;: &amp;quot;semi-dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 0&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: false,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:78&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:79&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:80&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 10,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:81&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:82&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:83&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 5,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS &#039;SW_Total_DC_P&#039;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_grid\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_grid&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_PV\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_PV&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_Battery\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_Battery&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Actual_Battery_charge_usable_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Actual_Battery_charge_usable_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_AC_Active_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_AC_Active_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;A&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Leistungsbezug&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Heizung&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Heizung value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Pool&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Waschmaschine&amp;quot;: &amp;quot;light-red&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 12&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hideEmpty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;hideZero&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: true,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;connected&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true,&lt;br /&gt;
          &amp;quot;steppedLine&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P_Max&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  abs(avg(value)) AS \&amp;quot;Heizung\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;StromZaehler_Heizung&#039; AND\n  READING = &#039;SMAEM1901401955_Saldo_Wirkleistung&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;StromZaehler_Heizung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SMAEM1901401955_Saldo_Wirkleistung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Pool\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly02&#039; AND\n  READING = &#039;Power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly02&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Waschmaschine\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly03&#039; AND\n  READING = &#039;power&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly03&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Brunnen\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Brunnen&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Shaun\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_1&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Shaun&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hauptverbraucher&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0&amp;quot;: &amp;quot;super-light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0 value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1 value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East value&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South value&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West&amp;quot;: &amp;quot;light-purple&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West value&amp;quot;: &amp;quot;super-light-purple&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 13,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 24&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: null,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc0\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc0&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc1\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc1&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc1&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_sumOfAllPVInputs\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_sumOfAllPVInputs&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_DC_Sum&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Solar_Calculation\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_Ost\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_Ost&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_Ost&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_Ost&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_Sued\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_Sued&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_Sued&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_Sued&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Forecast/Prognose&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;16000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;refresh&amp;quot;: &amp;quot;5m&amp;quot;,&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 27,&lt;br /&gt;
  &amp;quot;style&amp;quot;: &amp;quot;dark&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [],&lt;br /&gt;
  &amp;quot;templating&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: []&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;time&amp;quot;: {&lt;br /&gt;
    &amp;quot;from&amp;quot;: &amp;quot;now-1d/d&amp;quot;,&lt;br /&gt;
    &amp;quot;to&amp;quot;: &amp;quot;now-1d/d&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timepicker&amp;quot;: {&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;refresh_intervals&amp;quot;: [&lt;br /&gt;
      &amp;quot;5s&amp;quot;,&lt;br /&gt;
      &amp;quot;10s&amp;quot;,&lt;br /&gt;
      &amp;quot;30s&amp;quot;,&lt;br /&gt;
      &amp;quot;1m&amp;quot;,&lt;br /&gt;
      &amp;quot;5m&amp;quot;,&lt;br /&gt;
      &amp;quot;15m&amp;quot;,&lt;br /&gt;
      &amp;quot;30m&amp;quot;,&lt;br /&gt;
      &amp;quot;1h&amp;quot;,&lt;br /&gt;
      &amp;quot;2h&amp;quot;,&lt;br /&gt;
      &amp;quot;1d&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timezone&amp;quot;: &amp;quot;utc&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;PV_Anlage_1&amp;quot;,&lt;br /&gt;
  &amp;quot;uid&amp;quot;: &amp;quot;W-Y51Dmgk&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: 105&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit SVG==&lt;br /&gt;
Die Diagramme werden bei mir nicht mehr weiterentwickelt, da ich auf Grafana umgestiegen bin. Sie stehen hier nur noch als Beispiele für den Anfang.&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Total_PV_P_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_Battery::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB WR_1:SW_Actual_battery_charge_usable_P::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_Max::&lt;br /&gt;
#LogDB WR_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:max_month_SW_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_&amp;lt;Wohnort&amp;gt;_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB WR_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_sumOfAllPVInputs::&lt;br /&gt;
#LogDB WR_1:Solar_Calculation::&lt;br /&gt;
#LogDB WR_1:Solar_East::&lt;br /&gt;
#LogDB WR_1:Solar_South::&lt;br /&gt;
#LogDB WR_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power_(sumOfAllPVInputs)&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV_Perl (DOIF Modul) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 1                                   ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                     ## Die LWP ist aus\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]           ## Die maximale Laufzeit der LWP ist noch nicht erreicht\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## Das Maximum des PV-Modus ist noch nicht erreicht\&lt;br /&gt;
     and [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]   ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : LWP on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;LWP_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;PV_Modus_Ein_LWP();;set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;)&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : LWP on for manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : LWP off after manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]          ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : LWP off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; 100                              ## es soll noch eine Reserve bleiben\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : LWP off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;gt; 0                                  ## läuft eine Wartezeit\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 5                                  ## läuft die Wartezeit bald ab\&lt;br /&gt;
     and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot;\&lt;br /&gt;
      and [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe läuft&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer LWP &amp;quot;.get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;)};;\&lt;br /&gt;
    del_Exec(&amp;quot;LWP_Ein_timer&amp;quot;);;                                           ## Die LWP wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
## Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_1_LWP_Nachheizen_WW\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [[$SELF:TimeEnd]]                                               ## Am Ende der möglichen PV Steuerung\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt;= 48                             ## wenn das Wasser noch nicht im Sollbereich ist\&lt;br /&gt;
     and\&lt;br /&gt;
        (   [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]        ## Die maximale Laufzeit der LWP/Tag ist noch nicht erreicht\&lt;br /&gt;
         or [LWP_Counter:countsPerDay] eq 0)                             ## oder die LWP ist noch gar nicht gelaufen\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_LWP_Nachheizen_WW&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP on for water heating&amp;quot;};;\&lt;br /&gt;
                                                                         ## Es wird die Soll Temperatur um die Hysterese angehoben \&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget &amp;quot;.(ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,48)+4));;\&lt;br /&gt;
                                                                         ## Das zurücksetzen auf den Standard von 50° erfolgt generell beim Abschalten\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Hohe Priorität im Winter für die LWP\&lt;br /&gt;
## Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_2_LWP_Prioritaet_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [WR_1:SW_Total_PV_P_reserve] &amp;gt;= 2000                            ## es besteht jedoch noch eine Reserve und der\&lt;br /&gt;
     and [shelly02:power_0] &amp;gt; 800                                        ## Pool wird gerade aufgeheizt, was im Winter auch in der Nacht passiert\&lt;br /&gt;
     and [WR_1:Act_state_of_charge] &amp;gt; 60                                 ## Der Speicher sollte schon 60 % gefüllt sein\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## und die WW Temperatur noch unter 60°\&lt;br /&gt;
     and [$SELF:LWP_Priority] eq &amp;quot;frei&amp;quot;                                  ## Aber nur einmal am Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_LWP_Prioritaet_An&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_2 : LWP Priorität&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___LWP_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
        or [$SELF:LWP_Status] eq &amp;quot;manuell&amp;quot;\&lt;br /&gt;
       )\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimeMin]\&lt;br /&gt;
     and ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___LWP_Ende&amp;quot;                           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 05__ : LWP run finished&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Priorität für LWP wieder frei geben, damit einmal am Tag der PV-Modus verwendet werden kann\&lt;br /&gt;
##\&lt;br /&gt;
06___LWP_Prioritaet_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [23:55]\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;06___LWP_Prioritaet_Reset&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 06__ : LWP Priorität frei&amp;quot;};;\&lt;br /&gt;
     set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;frei&amp;quot;);;                                 ## Der PV-Modus darf wieder verwendet weden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## In der Überganszeit wird die Heizung kurz vor der PV-Zeit wieder ein geschaltet\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_1_Heizung_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeStartHeizung]]                                        ## Einschalten der Heizung, damit aus dem Puffer nachgeheizt wird 02:03\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_1_Heizung_An&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_1 : LWP Heizung Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHeating Auto&amp;quot;);;                  ## Die Heizungssteuerung erfolgt wieder Automatisch\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_2_Heizung_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeEndHeizung]]                                          ## Abschalten der Heizung, damit der Puffer für morgens Heizreserve hat\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_2_Heizung_Aus&amp;quot;                        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 07_2 : LWP Heizung aus&amp;quot;};;\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;Heizung opModeHeating Off&amp;quot;);;                     ## Die Heizung wird komplett abgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
   if (    [WR_1:Solar_Calculation_fc1_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] ## Auch morgen ist das Wetter schlecht\&lt;br /&gt;
       and [Heizung:averageAmbientTemperature] &amp;lt;= 5.6 ) {                ## Die Heizgrenze ist schon ziemlich tief\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungWinter]);;    ## Im Winter bis in die Morgenstunden den Accu sparen\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 07_2 : Parameter: &amp;quot;.[WR_1:Solar_Calculation_fc1_day].&amp;quot; &amp;lt; &amp;quot;.[WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit].&amp;quot; and &amp;quot;.[Heizung:averageAmbientTemperature].&amp;quot; &amp;lt;= 5.6&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungUebergang]);; ## Bei schönerem Wetter erst später Heizen\&lt;br /&gt;
     }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_2 : TimeStartHeizung switched to &amp;quot;.[$SELF:TimeStartHeizung]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 15°\&lt;br /&gt;
##\&lt;br /&gt;
07_3_Heizung_WZ_15_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_3_Heizung_WZ_15_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_3 : Heizung WZ 15 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 15&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 22°\&lt;br /&gt;
##\&lt;br /&gt;
07_4_Heizung_WZ_22_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_4_Heizung_WZ_22_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_4 : Heizung WZ 22 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 22&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung aus\&lt;br /&gt;
##\&lt;br /&gt;
07_5_Warmwasser_aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_5_Warmwasser_aus&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_5 : LWP Warmwasser aus&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Off&amp;quot;);;                  ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation inactive&amp;quot;);;                      ## Zirkulation ebenfalls abschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung auf Automatik\&lt;br /&gt;
##\&lt;br /&gt;
07_6_Warmwasser_an\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_6_Warmwasser_an&amp;quot;                      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_6 : LWP Warmwasser Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Auto&amp;quot;);;                 ## Die Warmwassersteuerung erfolgt wieder automatisch\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation active&amp;quot;);;                        ## Zirkulation wieder einschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_LWP() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP on&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 60.0&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;verwendet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_LWP() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 50.0&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr LWP_PV_Perl DbLogExclude .*&lt;br /&gt;
attr LWP_PV_Perl DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV_Perl alias LWP_PV_Perl&lt;br /&gt;
attr LWP_PV_Perl comment Version 2023.01.18 09:00&lt;br /&gt;
attr LWP_PV_Perl disable 0&lt;br /&gt;
attr LWP_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV_Perl icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV_Perl room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV_Perl sortby 411&lt;br /&gt;
attr LWP_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|::ReadingsTimestamp(&amp;quot;Heizung&amp;quot;,&amp;quot;counterHeatQTotal&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Status / LWP Status / Brauchwasser&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,04_1_LWP_Nachheizen_WW,04_2_LWP_Prioritaet_An,05___LWP_Ende,06___LWP_Prioritaet_Reset,07_1_Heizung_An,07_2_Heizung_Aus,07_3_Heizung_WZ_15_Grad,07_4_Heizung_WZ_22_Grad,07_5_Warmwasser_aus,07_6_Warmwasser_an&amp;quot;) |[Heizung:opStateHeatPump1].&amp;quot; &amp;quot;.[Heizung:opStateHeatPump2]|[Heizung:opStateHeatPump3]|FUNC_Status([Heizung:hotWaterTemperature],47,&amp;quot;orange&amp;quot;,[Heizung:hotWaterTemperature],&amp;quot;green&amp;quot;,[Heizung:hotWaterTemperature],53,&amp;quot;red&amp;quot;,[Heizung:hotWaterTemperature]).&amp;quot; °C&amp;quot;\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;PV-Modus / Heiz-Modus / Winter, Übergangszeit Heiz Start/Ende&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;PV-Modus:&amp;lt;br&amp;gt;&amp;quot;.[$SELF:LWP_Priority].&amp;quot; / &amp;quot;.(([$SELF:LWP_Status] ne &amp;quot;Aus&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039;)|&amp;quot;Heizung: &amp;quot;.[Heizung:opModeHeating].&amp;quot;&amp;lt;br&amp;gt;Warmwasser: &amp;quot;.[Heizung:opModeHotWater]|widget([$SELF:TimeStartHeizungWinter],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartHeizungUebergang],&amp;quot;time&amp;quot;)|[$SELF:TimeStartHeizung].widget([$SELF:TimeEndHeizung],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;Statistiken&amp;quot;|&amp;quot;Zähler&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Information&amp;quot;|&amp;quot;Wert&amp;quot;\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;EVU&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[EVU_StromZaehler:Strom_Status-02])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;LWP/KWL&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung_Zaehler])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHeating])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Warmwasser&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHotWater])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Photovoltaik&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQPool])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQTotal])\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 23:55:00 LWP_Priority frei&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-29 15:37:06 LWP_Status Aus&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 12:21:48 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 3000&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 2250&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-25 19:00:12 RunTimeMin 2400&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:55:35 RunTimePerDay 28800&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:37 TimeEnd 15:05&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 13:24:01 TimeEndHeizung 18:35&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:19 TimeStart 11:30&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 18:35:00 TimeStartHeizung 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:37:59 TimeStartHeizungUebergang 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:34:08 TimeStartHeizungWinter 02:05&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-31 12:05:34 ui_command_1 ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.54&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP&lt;br /&gt;
attr shelly01 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 412&lt;br /&gt;
attr shelly01 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung_Zaehler&amp;quot;,0));;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Wärmepumpe Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly01 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{4}(\.[0-9]{1})*$ StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{1,3}(\.[0-9]{1})*$&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter comment Version 2021.01.09 11:16&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 413&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39001</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=39001"/>
		<updated>2024-01-22T14:54:02Z</updated>

		<summary type="html">&lt;p&gt;Ch.eick: /* Device Übersicht mit Hilfen zur Orientierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Kostal Flow.PNG|mini|700px|rechts|Sowas könnte am Schluss raus kommen. Schreibt mich gerne an ;-)]]&lt;br /&gt;
{{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Perl]]&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|700px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|700px|rechts|]]&lt;br /&gt;
[[Bild:WR 1.PNG|mini|900px|rechts|Wechselrichter 1 mit Status]]&lt;br /&gt;
[[Bild:WR 1 Speicher 1.PNG|mini|900px|rechts|WR_1_Speicher_1_ExternControl]]&lt;br /&gt;
[[Bild:WR 2.PNG|mini|900px|rechts|Wechselrichter 2 und gesteuerte Geräte]]&lt;br /&gt;
[[Bild:Kia.PNG|mini|900px|rechts|WallBox mit Kia Fahrzeug]]&lt;br /&gt;
[[Bild:Geräte.PNG|mini|900px|rechts|PV gesteuerte Geräte]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus|Kostal Plenticore Plus]] ([https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/plenticore-plus/ Webseite des Herstellers]) ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen Energietechnik==&lt;br /&gt;
Der Wechselrichter, Speicher und KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
==Geräte-Registrierung==&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
Weiterhin ist der Betreiber verpflichtet, eine Anmeldung im Marktstammdatenregister vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hersteller Dokumentation==&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/14/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2021/02/04/10/49/lf_verschaltung-mehrerer-kostal-wechselrichter_de.pdf/ Plenticore Plus - Verschaltung und Einrichtung mehrerer KOSTAL-Wechselrichter]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/06/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/06/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/42/kostal_update_plenticore_piko_iq_012106586.swu/ Plenticore Plus - Software Update 01.21]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/download/-/media/document-library-folder---kse/2020/12/15/13/38/ba_kostal-interface-description-modbus-tcp_sunspec_hybrid.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/13/41/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/13/kostal_update_ksem_1_3_0.raucb/ KSEM - Software Update - 1.3.0]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/12/15/14/22/ba_kostal_interface_ksem_de.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
==Kompatibilität zu anderen Kostal Wechselrichtern==&lt;br /&gt;
Auf Grund von Anfragen scheint diese Implementierung auch für andere Kostal Wechselrichtern zu passen.&lt;br /&gt;
- Plenticore Plus &lt;br /&gt;
- Piko MP&lt;br /&gt;
- Piko IQ&lt;br /&gt;
Dies hängt natürlich mit der Firmware zusammen und es gibt sicherlich noch einige Anpassungen die notwendig sind. Bitte tragt Eure kompatieblen Geräte hier ein.&lt;br /&gt;
&lt;br /&gt;
==Einbindung in das Netzwerk==&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
==Namensgebung==&lt;br /&gt;
Im Laufe der Zeit hat sich herausgestellt, dass es einfacher ist, die hier vorgeschlagenen Namen zu übernehmen. Es vereinfacht die Kommunikation bei der Hilfestellung und erspart einigen Umbenennungsaufwand, da es doch immer wieder zu Anpassungen kommt. Leider musste in der letzten Zeit durch das Wachsen des Umfeldes und durch anfängliche Unwissenheit auch viel aufgeräumt werden.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen FHEM Umfeld==&lt;br /&gt;
===Alle Geräte müssen mit TCP/IP erreichbar sein===&lt;br /&gt;
===Alle Module sollten auf einem aktuellen Stand sein===&lt;br /&gt;
===Eine DbLog/DbRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird===&lt;br /&gt;
Es wurde immer wieder gefragt, ob man auch FileLog verwenden könnte, was grundsätzlich natürlich geht. Im Fortschreiten wird dies jedoch ziemlich unhandlich und vom Modulautor nicht empfohlen. Spätestens wenn die Daten mal aufgeräumt werden sollen, ist man mit einer MySQL Datenbank im Vorteil. Auch die Aufbereitung von Diagrammen ist mit einer Datenbank flexibler.&lt;br /&gt;
Weiterhin wird empfohlen eine vollwertige MySQL Datenbank zu verwenden, damit auch komplexeres Reporting im vollen SQL Umfang zur Verfügung steht. Beim Einsatz von SQLite sind bereits zumindest bei den Reports inkompatibilitäten aufgetreten. MariaDB sollte immer auch aktuell gehalten werden, was auf einem RPI 32 Bit nicht immer gewährleistet ist. Die größte aktualität erhält man mit dem original MySQL Docker Container, der auch auf einem RPI4 64 Bit verfügbar ist. Beim Einsatz einer Datenbank sollte man dies auf keinen Fall auf einer SD-Card machen. die besten Ergebnisse für Geschwindigkeit und Langlebigkeit bekommt man mit einer SSD.&lt;br /&gt;
&lt;br /&gt;
===Verwendete Module===&lt;br /&gt;
* Modbus&lt;br /&gt;
* HTTPMOD&lt;br /&gt;
* expandJSON&lt;br /&gt;
* DbLog&lt;br /&gt;
* DbRep&lt;br /&gt;
* DUMMY&lt;br /&gt;
* DOIF&lt;br /&gt;
* Shelly&lt;br /&gt;
* SMAEM&lt;br /&gt;
* HourCounter&lt;br /&gt;
* DWD_OpenData&lt;br /&gt;
* readingsGroup&lt;br /&gt;
* WeekdayTimer&lt;br /&gt;
* SVG&lt;br /&gt;
&lt;br /&gt;
===Verwendetes Umfeld===&lt;br /&gt;
* Raspberry Pi 4&lt;br /&gt;
* Debian&lt;br /&gt;
* Docker&lt;br /&gt;
:: fhem/fhem:latest&lt;br /&gt;
:: mysql/mysql-server&lt;br /&gt;
:: grafana/grafana:latest&lt;br /&gt;
* Perl&lt;br /&gt;
* Python&lt;br /&gt;
&lt;br /&gt;
==Einbindung in FHEM: Überblick==&lt;br /&gt;
&lt;br /&gt;
===MySQL etwas Basis Information===&lt;br /&gt;
====Docker Compose nach installieren====&lt;br /&gt;
Falls Docker Compose nicht bereits installiert ist.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ sudo apt-get install docker-compose&lt;br /&gt;
Paketlisten werden gelesen... Fertig&lt;br /&gt;
Abhängigkeitsbaum wird aufgebaut.&lt;br /&gt;
Statusinformationen werden eingelesen.... Fertig&lt;br /&gt;
docker-compose ist schon die neueste Version (1.21.0-3).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
https://docs.docker.com/engine/reference/commandline/compose/&lt;br /&gt;
&lt;br /&gt;
Einige Docker Kommandos:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Für den Überblick:&lt;br /&gt;
     docker stats&lt;br /&gt;
     docker ps&lt;br /&gt;
&lt;br /&gt;
Zum aktualisieren (nur ein Beispiel):&lt;br /&gt;
     docker pull portainer/portainer:latest&lt;br /&gt;
     docker-compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL Docker Container mit .yml====&lt;br /&gt;
Hier wäre mal ein Beispiel, wie die MySQL Datenbank innerhalb einer .yml Datei im Docker definiert werden kann. Im Beispiel ist FHEM und Portainer ebenfalls enthalten, wodurch dies auch somit eine Basis Installation sein könnte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~/docker-compose/fhem_2022 $ cat docker-compose.yml&lt;br /&gt;
# This is an exmaple Docker Compose file to start your own Docker Stack&lt;br /&gt;
&lt;br /&gt;
version: &#039;3.3&#039;&lt;br /&gt;
&lt;br /&gt;
volumes:&lt;br /&gt;
  portainer_data:&lt;br /&gt;
&lt;br /&gt;
services:&lt;br /&gt;
&lt;br /&gt;
  fhem:&lt;br /&gt;
    image: fhem/fhem:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
#    network_mode: host&lt;br /&gt;
#    privileged: true&lt;br /&gt;
#    devices:&lt;br /&gt;
#      - &amp;quot;/dev/ttyACM0:/dev/ttyACM0&amp;quot;&lt;br /&gt;
    volumes:&lt;br /&gt;
      - &amp;quot;./fhem/:/opt/fhem/&amp;quot;&lt;br /&gt;
#      - &amp;quot;./fhem/contrib/configDB/configDB.conf:/opt/fhem/configDB.conf&amp;quot;&lt;br /&gt;
    environment:&lt;br /&gt;
## Hier können gewünschte Zusatzpakete in den Container nachgeladen werden.&lt;br /&gt;
#      PIP_PKGS: &amp;quot;vallox_websocket_api fhem beautifulsoup4&amp;quot;&lt;br /&gt;
#      CPAN_PKGS: &amp;quot;Crypt::OpenSSL::AES XML::Bare XML::Bare Protocol::WebSocket::Handshake::Server Crypt::Rijndael Crypt::Random --verbose&amp;quot;&lt;br /&gt;
###########&lt;br /&gt;
      FHEM_UID: 6061&lt;br /&gt;
      FHEM_GID: 6061&lt;br /&gt;
      TIMEOUT: 10&lt;br /&gt;
      RESTART: 1&lt;br /&gt;
      TELNETPORT: 7072&lt;br /&gt;
      TZ: Europe/Berlin&lt;br /&gt;
#      CONFIGTYPE: configDB&lt;br /&gt;
    depends_on:&lt;br /&gt;
      - &amp;quot;mysql&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  mysql:&lt;br /&gt;
    image: mysql/mysql-server&lt;br /&gt;
    restart: always&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &#039;3306:3306&#039;&lt;br /&gt;
      - &#039;33060:33060&#039;&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/fhem-init.sql&lt;br /&gt;
      - ./mysql/data:/var/lib/mysql&lt;br /&gt;
      - ./mysql/log:/var/log&lt;br /&gt;
      - ./mysql/mycustom.cnf:/etc/mysql/conf.d/custom.cnf&lt;br /&gt;
    environment:&lt;br /&gt;
#      TZ: Europe/Berlin&lt;br /&gt;
      MYSQL_ROOT_PASSWORD: &amp;lt;root Passwort&amp;gt;&lt;br /&gt;
#      MYSQL_ROOT_HOST: 172.*.*.*&lt;br /&gt;
      MYSQL_DATABASE: fhem&lt;br /&gt;
      MYSQL_USER: fhemuser&lt;br /&gt;
      MYSQL_PASSWORD: &amp;lt;fhemuser Passwort&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  portainer:&lt;br /&gt;
    image: portainer/portainer:latest&lt;br /&gt;
    restart: always&lt;br /&gt;
    ports:&lt;br /&gt;
        - &#039;9000:9000&#039;&lt;br /&gt;
    environment:&lt;br /&gt;
      - REGISTRY_HTTP_TLS_CERTIFICATE=/certs/portainer.crt&lt;br /&gt;
      - REGISTRY_HTTP_TLS_KEY=/certs/portainer.key&lt;br /&gt;
    volumes:&lt;br /&gt;
      - /var/run/docker.sock:/var/run/docker.sock&lt;br /&gt;
      - portainer_data:/data&lt;br /&gt;
      - ./certs/portainer.key:/certs/portainer.key&lt;br /&gt;
      - ./certs/portainer.crt:/certs/portainer.crt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Administration etwas erleichtern====&lt;br /&gt;
In der /etc/passwd habe ich dann noch ein Login und die Home Verzeichnisse für einige Container eingetragen. Somit kann man sich dann auf dem Basis Betriebsystem mit diesem Benutzer anmelden und das Dateisystem des Docker Containers direkt bearbeiten. Der Home Path muss natürlich angepasst werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ cat /etc/passwd&lt;br /&gt;
&amp;lt; snip &amp;gt;&lt;br /&gt;
fhem:x:6061:6061:FHEM,,,:/home/pi/docker-compose/fhem_2024/fhem:/bin/bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====MySQL initial konfigurieren====&lt;br /&gt;
Wenn der MySQL Docker Container läuft sind dort noch die Basis Konfigurationen für DbLog durchzuführen, für die es ein eigenes FHEM Wiki gibt. Einige wichtige Kommandos sollen nun jetzt hier trotzdem aufgelistet werden.&lt;br /&gt;
=====MySQL Docker Console für MySQL root Login=====&lt;br /&gt;
Achtung&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Basis Konfiguration wird mit dem Benutzer root im MySQL durchgeführt und dieser kann sich bei Oracle MySQL nur lokal, also nicht aus dem Netz anmelden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dazu gibt es zwei Varianten:&lt;br /&gt;
1. Über den Docker Container anmelden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
pi@raspberrypi:~ $ docker exec -it fhem_2022_mysql_1 mysql -u root -p&lt;br /&gt;
Enter password:&lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 17517&lt;br /&gt;
Server version: 8.0.32 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Oder man meldet sich am Portainerzugang (admin mit &amp;lt;Passwort&amp;gt;) an und selectiert den MySQL Container. Dort kann man dann mit der Console in den Container wechseln.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
bash-4.4# mysql -u root -p&lt;br /&gt;
Enter password: &lt;br /&gt;
Welcome to the MySQL monitor.  Commands end with ; or \g.&lt;br /&gt;
Your MySQL connection id is 44892&lt;br /&gt;
Server version: 8.0.28 MySQL Community Server - GPL&lt;br /&gt;
mysql&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====MySQL Kommandos=====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
-- Die fhem Datenbank neu anlegen&lt;br /&gt;
mysql&amp;gt; CREATE DATABASE `fhem` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;&lt;br /&gt;
&lt;br /&gt;
-- Die FHEM Tabellen neu anlegen&lt;br /&gt;
-- Für die Spalte VALUE wurde mal eine längere Definition gewählt&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(255), UNIT varchar(32));&lt;br /&gt;
mysql&amp;gt; CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));&lt;br /&gt;
&lt;br /&gt;
-- Den Index einrichten und über das READING mit definieren, damit kein duplicate Key entstehen kann&lt;br /&gt;
mysql&amp;gt; CREATE INDEX Search_Idx ON `fhem`.`history` (TIMESTAMP, DEVICE, READING) USING BTREE;&lt;br /&gt;
Query OK, 0 rows affected (0.11 sec)&lt;br /&gt;
Records: 0  Duplicates: 0  Warnings: 0&lt;br /&gt;
&lt;br /&gt;
-- Im Oracle MySQL wird im Standard das Passwort in einer anderen Verschlüsselung abgeregt, die FHEM noch nicht unterstützt&lt;br /&gt;
-- Deshalb kann es erforderlich sein das Passwort, nach Änderung der Verschlüsselungsmethode neu zu setzen&lt;br /&gt;
mysql&amp;gt; DROP USER fhemuser;&lt;br /&gt;
mysql&amp;gt; CREATE USER &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Nachschauen welche Passwort Verschlüsselung verwendet wird&lt;br /&gt;
-- FHEM unterstützt nur mysql_native_password&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | caching_sha2_password |     &amp;lt;&amp;lt;&amp;lt; Das unterstützt FHEM mit DbLog noch nicht&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; UPDATE mysql.user SET plugin = &#039;mysql_native_password&#039; WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; SELECT Host,User,plugin FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| Host | User     | plugin                |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
| %    | fhemuser | mysql_native_password |&lt;br /&gt;
+------+----------+-----------------------+&lt;br /&gt;
1 row in set (0.01 sec)&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; ALTER USER &#039;fhemuser&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt; Password &amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Bei den GRANDS muss ich nochmal nachschauen, was da wirklich notwendig ist&lt;br /&gt;
mysql&amp;gt; GRANT SELECT, INSERT, DELETE, UPDATE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT ALTER ROUTINE ON `fhem`.* TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
mysql&amp;gt; GRANT EXECUTE ON PROCEDURE `fhem`.`dwd_load` TO &#039;fhemuser&#039;@&#039;%&#039;;&lt;br /&gt;
&lt;br /&gt;
-- Die Änderungen müssen mit einem FLUSH in der aktuellen Session übernommen werden&lt;br /&gt;
mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
-- Alle Einträge für den fhemuser anschauen&lt;br /&gt;
mysql&amp;gt; SELECT * FROM mysql.user WHERE User=&#039;fhemuser&#039;;&lt;br /&gt;
  &amp;lt; snip &amp;gt;&lt;br /&gt;
  Es wird eine Tabelle mit den user Einträgen für fhemuser angezeigt, die man sich besser in voller Breite im Editor anschaut&lt;br /&gt;
&lt;br /&gt;
mysql&amp;gt; Connect fhem;&lt;br /&gt;
  Enter password: &lt;br /&gt;
  Connection id:    44902&lt;br /&gt;
  Current database: fhem&lt;br /&gt;
&lt;br /&gt;
-- Zum Test mal einige Einträge in der history anzeigen, wenn FHEM bereits was über DbLog geschieben hat&lt;br /&gt;
mysql&amp;gt; SELECT * FROM history LIMIT 1;&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | TIMESTAMP           | DEVICE           | TYPE    | EVENT | READING         | VALUE    | UNIT |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  | 2019-04-03 00:23:42 | EVU_StromZaehler | HTTPMOD | NULL  | Strom_Status-02 | 07152.96 |      |&lt;br /&gt;
  +---------------------+------------------+---------+-------+-----------------+----------+------+&lt;br /&gt;
  1 row in set (0.01 sec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hardware Anbindung (alles über LAN)===&lt;br /&gt;
====Kostal Plenticore Plus====&lt;br /&gt;
=====Kostal Plenticore Plus die Basis information (Modbus/TCP)=====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
&lt;br /&gt;
======Plenticore Modbus Definition======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein zweiter Wechselrichter====&lt;br /&gt;
Durch einen Vollausbau des Daches ist ein zweiter Wechselrichter hinzugekommen. Das hat einen Umbau dieser Wiki Seite erfordert, wodurch sich diverse Änderungen bei der Namensgebung ergeben haben. Es ist jedoch auch weiterhin möglich, nur eine AC-Quelle zu verwenden, was an einigen Stellen entweder einen Rückbau in den Devices erfordert oder man freundet sich mit etwas anderen reading Namen an.&lt;br /&gt;
&lt;br /&gt;
======Modbus Timeing======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1_config======&lt;br /&gt;
Dieses Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehreren Wechselrichtern kann man die Module mit ihren Ausrichtungen für die Leistungsprognose alle in die erste Konfiguration legen. So ergibt sich später eine gemeinsame Prognose für die gesamte PV-Anlage. Wenn man dies auf einzelne Konfigurationsdummys aufteilt, kann man für jeden Wechselrichter eine eigene Prognose erstellen. Eine Einzel- und Gesamtprognose wäre ebenfalls denkbar. Fragen dazu bitte im Forum stellen.&lt;br /&gt;
&lt;br /&gt;
In der readingList und setList können die Namen der Ausrichtung frei gewählt werden.&lt;br /&gt;
&lt;br /&gt;
Die default Einstellungen wurden bereits über Sommer und Winter getestet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_config dummy&lt;br /&gt;
attr WR_1_config DbLogExclude .*&lt;br /&gt;
attr WR_1_config alias WR_1_config&lt;br /&gt;
attr WR_1_config comment Version 2021.04.07 12:00\&lt;br /&gt;
Passworte für die Abfrage des WR_1_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
\&lt;br /&gt;
Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr WR_1_config event-on-change-reading .*&lt;br /&gt;
attr WR_1_config group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_config icon solar_icon&lt;br /&gt;
attr WR_1_config readingList IP-WR_1 IP-WR_1_Speicher_1 IP-WR_1_KSEM IP-FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name  module_4_name module_5_name module_1_direction module_2_direction module_3_direction module_4_direction module_5_direction module_1_count module_2_count module_3_count module_4_count module_5_count module_1_power module_2_power module_3_power module_4_power module_5_power module_1_plain module_2_plain module_3_plain module_4_plain module_5_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor forecast_factor_autocorrection Forecast_Station&lt;br /&gt;
attr WR_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_config setList IP-WR_1 IP-WR_1_Speicher_1 IP-WR_1_KSEM IP-FHEM module_1_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort module_2_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort module_3_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_4_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_5_name:WR_1_Ost,WR_1_West,WR_2_Sued,WR_2_West,East,SouthEast,South,SouthWest,West,Garage,CarPort,frei module_1_direction module_2_direction module_3_direction module_4_direction module_5_direction module_1_count module_2_count module_3_count module_4_count module_5_count module_1_power module_2_power module_3_power module_4_power module_5_power module_1_plain module_2_plain module_3_plain module_4_plain module_5_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor forecast_factor_autocorrection Forecast_Station&lt;br /&gt;
attr WR_1_config sortby 113&lt;br /&gt;
attr WR_1_config verbose 0&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_config 2020-09-11 07:36:39 Forecast_Station P0178&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:39:26 IP-FHEM 192.168.178.xxx&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:39:44 IP-WR_1 192.168.178.yyy&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:43:27 IP-WR_1_KSEM 192.168.178.zzz&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:44:46 IP-WR_1_Speicher_1 192.168.178.xyz&lt;br /&gt;
setstate WR_1_config 2020-09-22 10:03:21 forecast_cloudk 45&lt;br /&gt;
setstate WR_1_config 2020-09-22 10:12:17 forecast_cloudk_base 0&lt;br /&gt;
setstate WR_1_config 2020-12-07 15:49:18 forecast_factor 1&lt;br /&gt;
setstate WR_1_config 2021-03-31 11:45:19 forecast_factor_autocorrection 0&lt;br /&gt;
setstate WR_1_config 2020-09-02 18:40:29 forecast_raink 20&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:52:40 forecast_raink_base 0&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:46:57 forecast_tempk 39&lt;br /&gt;
setstate WR_1_config 2020-09-01 12:50:06 forecast_tempk_base 25&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:31:19 module_1_count 20&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:27:38 module_1_direction -90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:33:27 module_1_name WR_1_Ost&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:29:42 module_1_plain 40&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:31:09 module_1_power 310&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:10 module_2_count 16&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:13 module_2_direction 90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:33:45 module_2_name WR_1_West&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:34:14 module_2_plain 40&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:23:00 module_2_power 310&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:40 module_3_count 13&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:26 module_3_direction 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:34:09 module_3_name WR_2_Sued&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:35:08 module_3_plain 40&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:41:55 module_3_power 340&lt;br /&gt;
setstate WR_1_config 2021-03-29 12:20:49 module_4_count 11&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:54:37 module_4_direction 90&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:34:27 module_4_name WR_2_West&lt;br /&gt;
setstate WR_1_config 2020-08-31 12:34:14 module_4_plain 40&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:23:00 module_4_power 340&lt;br /&gt;
setstate WR_1_config 2021-02-04 12:41:15 module_5_count 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:53:22 module_5_direction 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:43:38 module_5_name frei&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:50:46 module_5_plain 0&lt;br /&gt;
setstate WR_1_config 2021-03-23 14:50:39 module_5_power 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 (bei einem Wechselrichtern)======&lt;br /&gt;
Generell kann die WR_1 und WR_1_API Definition, die im folgenden kommt auch für einen einzelnen Wechselrichter verwendet werden. Wer die readings für die Korrektur mit zwei AC-Quellen nicht haben möchte, der kann diese gerne wieder entfernen, was dann jedoch bei jedem Update immer wieder gemacht werden muss. Achtung es können dann jedoch Abweichungen bei der Plausibilität einzelner Readings auftreten. Alle stateFormat und weiteren DOIF Devices beziehen sich hierbei jedoch ebenfalls auf die SW_* readings, um die Implementierung für mehr Anwender verwendbar zu machen. Diejenigen unter Euch, die auch einen nicht Kostal Wechselrichter verwenden sollten sich bitte die userReadings anschauen, um dort die readings korrekt zu mappen. Es sollte auch kein Problem sein als zweite AC-Quelle ein Krafwärmekopplung ein zu binden.&lt;br /&gt;
&lt;br /&gt;
Anzupassende Stellen, wenn man lieber keinen Schwarm vorbereiten möchte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WR_1 und WR_1_API:&lt;br /&gt;
 - userReadings SW_* löschen&lt;br /&gt;
 - deletereading WR_1 SW_*&lt;br /&gt;
 - stateFormat bei readings mit SW_* das SW_ löschen&lt;br /&gt;
 - DbLogInclude überprüfen&lt;br /&gt;
 - event-on-update-reading überprüfen&lt;br /&gt;
PV_Schedule:&lt;br /&gt;
 - cmd_5 für die Zählerstände löschen&lt;br /&gt;
DbLog:&lt;br /&gt;
 - Eventuell die Datenbank aufräumen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_1 Master (bei zwei Wechselrichtern)======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
Es kann für einen einzelnen oder auch mehrere Wechselrichter verwendet werden. Readings mit SW_* korrigieren die bisher fehlerhaften Ausgabewerte der Kostal Wechselrichter im Schwarm. Bei Verwendung nur eines einzelnen Wechselrichters können diese jedoch auch verwendet werden. Die Original readings sind auch weiterhin noch vorhanden, was jedoch zu einer Befüllung mit gleichen Werten führen kann. Damit diese nicht doppelt in der Datenbank landen, kann man das DbLogInclude entsprechend anpassen, nachdem man sich entschieden hat, welche Richtung man einschlagen möchte.&lt;br /&gt;
Letzte Änderungen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Bei den readings wurden ungültige Zeichen aus den Namen entfernt, wie z.B. &amp;quot;()&amp;quot;&lt;br /&gt;
  Wer das bei sich ändert muss natürlich auch in der Datenbank aufräumen.&lt;br /&gt;
- Einige readings wurden eingekürzt z.B. P,U,I,L*&lt;br /&gt;
- SW_* gibt die korrigierten werte bei mehr als einer AC-Quelle an&lt;br /&gt;
- DbLogInclude logged nun auch SW_* und die eingekürzten reading Namen&lt;br /&gt;
- PV wurde zu WR, da eine PV-Anlage aus mehreren Wechselrichtern bestehen kann&lt;br /&gt;
- stateFormat und userReadings verwenden jetzt die SW_* readings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1 ModbusAttr 71 60 &amp;lt;IP-Adresse&amp;gt;:1502 TCP&lt;br /&gt;
attr WR_1 DbLogExclude .*&lt;br /&gt;
attr WR_1 DbLogInclude Act_state_of_charge,Actual_Battery_charge_-minus_or_discharge_-plus_P,Actual_Battery_charge_usable_P,Battery_Total.*,Battery_charge.*,Battery_gross.*,Battery_temperature,Battery_MaxChargePowerLimitAbs,Battery_.*SOC,P_DC1,P_DC2,Total_.*,Solar_Calculation,Solar_Calculation_fc0_4h,Solar_Calculation_fc0_day,Solar_Calculation_fc0_rest,Solar_Correction.*,Solar_Cloud,Solar_East_Covered,Solar_Rain,Solar_SolarRadiation,Solar_Temp,Solar_WR_.*,Solar_middayhigh.*,SW_.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_1 alias WR_1&lt;br /&gt;
attr WR_1 alignTime 00:00&lt;br /&gt;
attr WR_1 comment Version 2022.12.30 10:00\&lt;br /&gt;
Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr WR_1 dev-h-combine 8&lt;br /&gt;
attr WR_1 dev-h-defFormat %.2f&lt;br /&gt;
attr WR_1 dev-h-defLen 2&lt;br /&gt;
attr WR_1 dev-h-defPoll 1&lt;br /&gt;
attr WR_1 dev-h-defRevRegs 1&lt;br /&gt;
attr WR_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr WR_1 dev-type-STR-format %s&lt;br /&gt;
attr WR_1 dev-type-STR-len 8&lt;br /&gt;
attr WR_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr WR_1 dev-type-STR-unpack a*&lt;br /&gt;
attr WR_1 disable 0&lt;br /&gt;
attr WR_1 event-on-change-reading Act_state_of_charge,Actual_Battery_charge_-minus_or_discharge_-plus_I,Actual_Battery_charge_-minus_or_discharge_-plus_P,Actual_Battery_charge_usable_P,Battery_Total.*,Battery_charge.*,Battery_gross.*,Battery_temperature,Battery_MaxChargePowerLimitAbs,Battery_.*SOC,Home_own_consumption.*,P_DC1,P_DC2,Solar_.*,Total_.*,SW_.*,.*_yield,Inverter_state.*,Inverter_Generation_P_Actual.*,Solar_Calculation_fc.*_day&lt;br /&gt;
attr WR_1 event-on-update-reading P_limit_from_EVU.*&lt;br /&gt;
attr WR_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1 icon sani_solar&lt;br /&gt;
attr WR_1 obj-h100-reading Total_DC_P&lt;br /&gt;
attr WR_1 obj-h1024-len 1&lt;br /&gt;
attr WR_1 obj-h1024-reading Battery_Charge_AC_P_Setpoint&lt;br /&gt;
attr WR_1 obj-h1024-set 1&lt;br /&gt;
attr WR_1 obj-h1024-unpack n&lt;br /&gt;
attr WR_1 obj-h1025-len 1&lt;br /&gt;
attr WR_1 obj-h1025-reading Battery_P_ScaleFactor&lt;br /&gt;
attr WR_1 obj-h1025-unpack n&lt;br /&gt;
attr WR_1 obj-h1026-reading Battery_Charge_AC_P_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1026-set 1&lt;br /&gt;
attr WR_1 obj-h1028-reading Battery_Charge_DC_I_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1028-set 1&lt;br /&gt;
attr WR_1 obj-h1030-reading Battery_Charge_AC_P_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1030-set 1&lt;br /&gt;
attr WR_1 obj-h1032-reading Battery_Charge_DC_I_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1032-set 1&lt;br /&gt;
attr WR_1 obj-h1034-reading Battery_Charge_DC_P_SetpointAbs&lt;br /&gt;
attr WR_1 obj-h1034-set 1&lt;br /&gt;
attr WR_1 obj-h1036-reading Battery_Charge_DC_P_SetpointRel&lt;br /&gt;
attr WR_1 obj-h1036-set 1&lt;br /&gt;
attr WR_1 obj-h1038-reading Battery_MaxChargePowerLimitAbs&lt;br /&gt;
attr WR_1 obj-h1038-set 1&lt;br /&gt;
attr WR_1 obj-h104-format %s&lt;br /&gt;
attr WR_1 obj-h104-map 0:Normal,8:Ruhe1,16:Ruhe2,32:Ausgleichsladung,64:Tiefentladeschutz,256:externe Batteriesteuerung&lt;br /&gt;
attr WR_1 obj-h104-reading State_of_EM&lt;br /&gt;
attr WR_1 obj-h104-revRegs 0&lt;br /&gt;
attr WR_1 obj-h104-unpack N&lt;br /&gt;
attr WR_1 obj-h1040-reading Battery_MaxDischargePowerLimitAbs&lt;br /&gt;
attr WR_1 obj-h1040-set 1&lt;br /&gt;
attr WR_1 obj-h1042-reading Battery_MinSOC&lt;br /&gt;
attr WR_1 obj-h1042-set 1&lt;br /&gt;
attr WR_1 obj-h1044-reading Battery_MaxSOC&lt;br /&gt;
attr WR_1 obj-h1044-set 1&lt;br /&gt;
attr WR_1 obj-h1046-reading Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
attr WR_1 obj-h1048-reading Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
attr WR_1 obj-h1050-reading Battery_Total_AC_ChargeEnergy_ACsideToBattery&lt;br /&gt;
attr WR_1 obj-h1052-reading Battery_Total_AC_DischargeEnergy_BatteryToGrid&lt;br /&gt;
attr WR_1 obj-h1054-reading Battery_Total_AC_ChargeEnergy_gridToBattery&lt;br /&gt;
attr WR_1 obj-h1056-reading Total_DC_PV_Energy_sumOfAllPVInputs&lt;br /&gt;
attr WR_1 obj-h1058-reading Total_DC_Energy_From_PV1&lt;br /&gt;
attr WR_1 obj-h106-reading Home_own_consumption_from_Battery&lt;br /&gt;
attr WR_1 obj-h1060-reading Total_DC_Energy_From_PV2&lt;br /&gt;
attr WR_1 obj-h1062-reading Total_DC_Energy_From_PV3&lt;br /&gt;
attr WR_1 obj-h1064-reading Total_AC_Energy_ACsideToGrid&lt;br /&gt;
attr WR_1 obj-h1066-reading Total_DC_P_sumOfAllPVInputs&lt;br /&gt;
attr WR_1 obj-h1068-reading Battery_work_capacity&lt;br /&gt;
attr WR_1 obj-h1070-reading Battery_serial_number&lt;br /&gt;
attr WR_1 obj-h1072-reading Battery_Reserved_1072&lt;br /&gt;
attr WR_1 obj-h1074-reading Battery_Reserved_1074&lt;br /&gt;
attr WR_1 obj-h1076-reading Battery_Maximum_ChargePLimit_read-outFromBattery&lt;br /&gt;
attr WR_1 obj-h1078-reading Battery_Maximum_DischargePLimit_read-outFromBattery&lt;br /&gt;
attr WR_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr WR_1 obj-h1080-reading Battery_management_mode&lt;br /&gt;
attr WR_1 obj-h1080-set 1&lt;br /&gt;
attr WR_1 obj-h1081-reading Battery_Reserved_1081&lt;br /&gt;
attr WR_1 obj-h1082-reading Installed_sensor_type&lt;br /&gt;
attr WR_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr WR_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr WR_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr WR_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr WR_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr WR_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr WR_1 obj-h122-reading P_limit_from_EVU&lt;br /&gt;
attr WR_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr WR_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr WR_1 obj-h14-type STR&lt;br /&gt;
attr WR_1 obj-h144-reading Worktime&lt;br /&gt;
attr WR_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr WR_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr WR_1 obj-h154-reading I_L1&lt;br /&gt;
attr WR_1 obj-h156-reading Active_P_L1&lt;br /&gt;
attr WR_1 obj-h158-reading U_L1&lt;br /&gt;
attr WR_1 obj-h160-reading I_L2&lt;br /&gt;
attr WR_1 obj-h162-reading Active_P_L2&lt;br /&gt;
attr WR_1 obj-h164-reading U_L2&lt;br /&gt;
attr WR_1 obj-h166-reading I_L3&lt;br /&gt;
attr WR_1 obj-h168-reading Active_P_L3&lt;br /&gt;
attr WR_1 obj-h170-reading U_L3&lt;br /&gt;
attr WR_1 obj-h172-reading Total_AC_Active_P&lt;br /&gt;
attr WR_1 obj-h174-reading Total_AC_Reactive_P&lt;br /&gt;
attr WR_1 obj-h178-reading Total_AC_Apparent_P&lt;br /&gt;
attr WR_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr WR_1 obj-h194-format %.0f&lt;br /&gt;
attr WR_1 obj-h194-reading Number_of_Battery_cycles&lt;br /&gt;
attr WR_1 obj-h200-reading Actual_Battery_charge_-minus_or_discharge_-plus_I&lt;br /&gt;
attr WR_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr WR_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr WR_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr WR_1 obj-h212-reading Battery_state&lt;br /&gt;
attr WR_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr WR_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr WR_1 obj-h218-reading Cos_phi_EM&lt;br /&gt;
attr WR_1 obj-h220-reading Frequency_EM&lt;br /&gt;
attr WR_1 obj-h222-reading I_L1_EM&lt;br /&gt;
attr WR_1 obj-h224-reading Active_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h226-reading Reactive_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h228-reading Apparent_P_L1_EM&lt;br /&gt;
attr WR_1 obj-h230-reading U_L1_EM&lt;br /&gt;
attr WR_1 obj-h232-reading I_L2_EM&lt;br /&gt;
attr WR_1 obj-h234-reading Active_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h236-reading Reactive_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h238-reading Apparent_P_L2_EM&lt;br /&gt;
attr WR_1 obj-h240-reading U_L2_EM&lt;br /&gt;
attr WR_1 obj-h242-reading I_L3_EM&lt;br /&gt;
attr WR_1 obj-h244-reading Active_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h246-reading Reactive_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h248-reading Apparent_P_L3_EM&lt;br /&gt;
attr WR_1 obj-h250-reading U_L3_EM&lt;br /&gt;
attr WR_1 obj-h252-reading Total_Active_P_EM&lt;br /&gt;
attr WR_1 obj-h254-reading Total_Reactive_P_EM&lt;br /&gt;
attr WR_1 obj-h256-reading Total_Apparent_P_EM&lt;br /&gt;
attr WR_1 obj-h258-reading I_DC1&lt;br /&gt;
attr WR_1 obj-h260-reading P_DC1&lt;br /&gt;
attr WR_1 obj-h266-reading U_DC1&lt;br /&gt;
attr WR_1 obj-h268-reading I_DC2&lt;br /&gt;
attr WR_1 obj-h270-reading P_DC2&lt;br /&gt;
attr WR_1 obj-h276-reading U_DC2&lt;br /&gt;
attr WR_1 obj-h278-reading I_DC3&lt;br /&gt;
attr WR_1 obj-h280-reading P_DC3&lt;br /&gt;
attr WR_1 obj-h286-reading U_DC3&lt;br /&gt;
attr WR_1 obj-h320-reading Total_yield&lt;br /&gt;
attr WR_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr WR_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr WR_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr WR_1 obj-h38-reading Software-Version_Maincontroller_MC&lt;br /&gt;
attr WR_1 obj-h38-type STR&lt;br /&gt;
attr WR_1 obj-h384-len 16&lt;br /&gt;
attr WR_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr WR_1 obj-h384-type STR&lt;br /&gt;
attr WR_1 obj-h4-format %.0f&lt;br /&gt;
attr WR_1 obj-h4-len 1&lt;br /&gt;
attr WR_1 obj-h4-reading MODBUS_Unit-ID&lt;br /&gt;
attr WR_1 obj-h4-revRegs 1&lt;br /&gt;
attr WR_1 obj-h4-unpack N&lt;br /&gt;
attr WR_1 obj-h420-reading IP-address&lt;br /&gt;
attr WR_1 obj-h420-type STR&lt;br /&gt;
attr WR_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr WR_1 obj-h428-type STR&lt;br /&gt;
attr WR_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr WR_1 obj-h436-type STR&lt;br /&gt;
attr WR_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr WR_1 obj-h446-type STR&lt;br /&gt;
attr WR_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr WR_1 obj-h454-type STR&lt;br /&gt;
attr WR_1 obj-h46-reading Software-Version_IO-Controller_IOC&lt;br /&gt;
attr WR_1 obj-h46-type STR&lt;br /&gt;
attr WR_1 obj-h5-format %.0f&lt;br /&gt;
attr WR_1 obj-h5-len 1&lt;br /&gt;
attr WR_1 obj-h5-reading MODBUS_Byte_Order_Note&lt;br /&gt;
attr WR_1 obj-h5-revRegs 1&lt;br /&gt;
attr WR_1 obj-h5-unpack N&lt;br /&gt;
attr WR_1 obj-h512-format %s&lt;br /&gt;
attr WR_1 obj-h512-reading Battery_gross_capacity&lt;br /&gt;
attr WR_1 obj-h512-unpack N&lt;br /&gt;
attr WR_1 obj-h514-len 1&lt;br /&gt;
attr WR_1 obj-h514-reading Battery_Actual_SOC&lt;br /&gt;
attr WR_1 obj-h514-unpack n&lt;br /&gt;
attr WR_1 obj-h515-format %s&lt;br /&gt;
attr WR_1 obj-h515-reading Battery_Maincontroller_MC&lt;br /&gt;
attr WR_1 obj-h515-unpack N&lt;br /&gt;
attr WR_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr WR_1 obj-h517-type STR&lt;br /&gt;
attr WR_1 obj-h525-format %s&lt;br /&gt;
attr WR_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr WR_1 obj-h525-unpack N&lt;br /&gt;
attr WR_1 obj-h527-format %s&lt;br /&gt;
attr WR_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr WR_1 obj-h527-unpack N&lt;br /&gt;
attr WR_1 obj-h529-len 4&lt;br /&gt;
attr WR_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr WR_1 obj-h529-unpack N&lt;br /&gt;
attr WR_1 obj-h531-format %.0f&lt;br /&gt;
attr WR_1 obj-h531-reading Inverter_Max_P&lt;br /&gt;
attr WR_1 obj-h531-unpack N&lt;br /&gt;
attr WR_1 obj-h56-format %.0f&lt;br /&gt;
attr WR_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr WR_1 obj-h56-unpack N&lt;br /&gt;
attr WR_1 obj-h575-reading Inverter_Generation_P_Actual&lt;br /&gt;
attr WR_1 obj-h575-unpack N&lt;br /&gt;
attr WR_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr WR_1 obj-h577-unpack N&lt;br /&gt;
attr WR_1 obj-h578-reading Total_energy&lt;br /&gt;
attr WR_1 obj-h582-reading Actual_Battery_charge-discharge_P&lt;br /&gt;
attr WR_1 obj-h586-format %s&lt;br /&gt;
attr WR_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr WR_1 obj-h586-unpack N&lt;br /&gt;
attr WR_1 obj-h6-reading Inverter_Article_number&lt;br /&gt;
attr WR_1 obj-h6-type STR&lt;br /&gt;
attr WR_1 obj-h768-len 32&lt;br /&gt;
attr WR_1 obj-h768-reading Productname&lt;br /&gt;
attr WR_1 obj-h768-type STR&lt;br /&gt;
attr WR_1 obj-h800-len 32&lt;br /&gt;
attr WR_1 obj-h800-reading Power_class&lt;br /&gt;
attr WR_1 obj-h800-type STR&lt;br /&gt;
attr WR_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1 sortby 111&lt;br /&gt;
attr WR_1 stateFormat {\&lt;br /&gt;
 my $DUMMY  = &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $Power          = ReadingsVal($name,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_P&amp;quot;,0);;\&lt;br /&gt;
 my $StatusSpeicher = ($Power &amp;lt; -10) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot; : ($Power &amp;gt; 15)?  &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot;  : &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Standby&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
    $StatusSpeicher = $StatusSpeicher.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.ReadingsVal($name,&amp;quot;State_of_EM&amp;quot;,&amp;quot;n/a&amp;quot;);;\&lt;br /&gt;
    $Power          = $Power.&amp;quot; W&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
 my $Battery_temperature                  = sprintf(&amp;quot;%.1f °C&amp;quot;,ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0));;\&lt;br /&gt;
    $Battery_temperature                  = ((ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;DigitalOutputs_ConfigurationFlags&amp;quot;,0) == 9) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Lüfter An &amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;quot; : &amp;quot;&amp;lt;br&amp;gt;&amp;quot;).$Battery_temperature;;\&lt;br /&gt;
\&lt;br /&gt;
 my $Actual_Battery_charge_usable_P       = sprintf(&amp;quot;%d Wh&amp;quot;,ReadingsVal($name,&amp;quot;Actual_Battery_charge_usable_P&amp;quot;,0));;\&lt;br /&gt;
								         \&lt;br /&gt;
 my $Act_state_of_charge                  = sprintf(&amp;quot;%d %%&amp;quot;,ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
 my $SW_Total_DC_P_sumOfAllPVInputs       = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
 my $SW_Total_PV_P_reserve                = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Total_PV_P_reserve&amp;quot;,&amp;quot;0&amp;quot;));;\&lt;br /&gt;
\&lt;br /&gt;
 my $SW_Home_own_consumption_from_PV      = sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0));;\&lt;br /&gt;
    $SW_Home_own_consumption_from_PV = ($SW_Home_own_consumption_from_PV &amp;gt;= 0) ? $SW_Home_own_consumption_from_PV.&amp;quot; W&amp;quot; : &amp;quot;0 W&amp;quot;;;\&lt;br /&gt;
 my $SW_Home_own_consumption_from_Battery = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0));;\&lt;br /&gt;
 my $SW_Home_own_consumption_from_grid    = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0));;\&lt;br /&gt;
 my $SW_Home_own_consumption              = sprintf(&amp;quot;%d W&amp;quot;,ReadingsVal($name,&amp;quot;SW_Home_own_consumption&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
 my $Total_Active_P_EM  = sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;Total_Active_P_EM&amp;quot;,0));;\&lt;br /&gt;
 my $StatusNetz         = ($Total_Active_P_EM &amp;lt; -10) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;Einspeisen&amp;lt;/span&amp;gt;&amp;quot; : ($Total_Active_P_EM &amp;gt; 15)?  &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Netzbezug&amp;lt;/span&amp;gt;&amp;quot;  : &amp;quot;&amp;lt;span style=&#039;color:orange&#039;&amp;gt;Standby&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
    $Total_Active_P_EM  = $Total_Active_P_EM.&amp;quot; W&amp;quot;;;\&lt;br /&gt;
	 \&lt;br /&gt;
 my $SW_Yield_Daily   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Daily&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Monthly = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Monthly&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Yearly  = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Yearly&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $SW_Yield_Total   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;SW_Yield_Total&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
\&lt;br /&gt;
 my $Solar_Calculation_fc0_4h   = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_4h&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $Solar_Calculation_fc0_day  = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_day&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
 my $Solar_Calculation_fc0_rest = sprintf(&amp;quot;%d kWh&amp;quot;,round(ReadingsVal($name,&amp;quot;Solar_Calculation_fc0_rest&amp;quot;,0)/1000 ,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center;;font-weight:bold&#039;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Wechselrichter / KSEM&amp;lt;dd&amp;gt;Max DC / PV Reserve / Netz Leistung&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Total_DC_P_sumOfAllPVInputs.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Total_PV_P_reserve.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$StatusNetz.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Total_Active_P_EM.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Leistung&amp;lt;dd&amp;gt;von PV / von Batterie / vom Netz / ins Haus&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_PV.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_Battery.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption_from_grid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Home_own_consumption.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Ertrag&amp;lt;dd&amp;gt;Tag / Monat / Jahr / Total&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Daily.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Monthly.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Yearly.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$SW_Yield_Total.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Prognose&amp;lt;dd&amp;gt;Tag / 4 Stunden / Resttag&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_day.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_4h.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Solar_Calculation_fc0_rest.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$DUMMY.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Speicher&amp;lt;dd&amp;gt;Temperatur / nutzbare Ladung / Status / Leistung / akt. SOC&amp;lt;/dd&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Battery_temperature.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;lt;br&amp;gt;&amp;quot;.$Actual_Battery_charge_usable_P.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$StatusSpeicher.&amp;quot;&amp;lt;br&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$Power.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.$Act_state_of_charge.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1 userReadings Total_PV_P_reserve:Total_DC_P.* {my $reserve = ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0);;;; ($reserve lt 0)? 0 : round($reserve,0)  },\&lt;br /&gt;
\&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_P:[Battery_voltage|Actual_Battery_charge_-minus_or_discharge_-plus_I].* {round((ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_I&amp;quot;,0)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_P_Max:[Total_DC_P_sumOfAllPVInputs|Actual_Battery_charge_-minus_or_discharge_-plus_P].* { my $Bat_P = ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_P&amp;quot;,0);;;; ($Bat_P gt 0)? round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0) + $Bat_P,0) : round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_Battery_charge_usable_P:[Act_state_of_charge|Battery_MinSOC].* {my $x = (ReadingsVal($NAME,&amp;quot;Battery_work_capacity&amp;quot;,0)*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,0)-ReadingsVal($NAME,&amp;quot;Battery_MinSOC&amp;quot;,0))/100);;;; ($x lt 0)? 0 : round($x,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Inverter_Generation_P_Actual:Inverter_Generation_P_Actual.* {round(ReadingsVal($NAME,&amp;quot;Inverter_Generation_P_Actual&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Inverter_Generation_P_Actual&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption:[Total_Active_P_EM:|Total_AC_Active_P:].* {round(ReadingsVal($NAME,&amp;quot;Total_Active_P_EM&amp;quot;,0)+ReadingsVal($NAME,&amp;quot;Total_AC_Active_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Active_P&amp;quot;,0),0)},\&lt;br /&gt;
SW_Total_AC_Active_P:Total_AC_Active_P:.*  {round(ReadingsVal($NAME,&amp;quot;Total_AC_Active_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Active_P&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P:Total_DC_P:.* {round(ReadingsVal($NAME,&amp;quot;Total_DC_P&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_P&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P_sumOfAllPVInputs:Total_DC_P_sumOfAllPVInputs.* {round(ReadingsVal($NAME,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_PV_P_reserve:SW_Total_DC_P_sumOfAllPVInputs.* {my $reserve = ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0) * 0.90 - ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0);;;; ($reserve lt 0)? 0 : round($reserve,0)  },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_P_Max:SW_Total_DC_P_sumOfAllPVInputs.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_Battery_charge_-minus_or_discharge_-plus_I&amp;quot;,0)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,0));;;; ($Bat_out gt 0)? round(ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0) + $Bat_out,0) : round(ReadingsVal($NAME,&amp;quot;SW_Total_DC_P_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Yield_Daily:Daily_yield.* { round(ReadingsVal($NAME,&amp;quot;Daily_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Daily_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Monthly:Monthly_yield.* { round(ReadingsVal($NAME,&amp;quot;Monthly_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Monthly_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Yearly:Yearly_yield.* { round(ReadingsVal($NAME,&amp;quot;Yearly_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Yearly_yield&amp;quot;,0),0) },\&lt;br /&gt;
SW_Yield_Total:Total_yield.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_yield&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_yield&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption_from_PV:[Total_Active_P_EM|SW_Home_own_consumption:|Home_own_consumption_from_grid|Home_own_consumption_from_Battery].* { (ReadingsVal($NAME,&amp;quot;Total_Active_P_EM&amp;quot;,0) ge 0) ? ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0) :  ReadingsVal($NAME,&amp;quot;SW_Home_own_consumption&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0);;;; },\&lt;br /&gt;
\&lt;br /&gt;
SW_Home_own_consumption_from_Battery:[SW_Home_own_consumption_from_PV|Home_own_consumption_from_Battery].* { ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_Battery&amp;quot;,0) },\&lt;br /&gt;
SW_Home_own_consumption_from_grid:[SW_Home_own_consumption_from_PV|Home_own_consumption_from_grid].* { ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0) },\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Battery_Total_AC_ChargeEnergy_ACsideToBattery:Battery_Total_AC_ChargeEnergy_ACsideToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_ChargeEnergy_ACsideToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_AC_ChargeEnergy_gridToBattery:Battery_Total_AC_ChargeEnergy_gridToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_ChargeEnergy_gridToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_AC_DischargeEnergy_BatteryToGrid:Battery_Total_AC_DischargeEnergy_BatteryToGrid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_AC_DischargeEnergy_BatteryToGrid&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_DC_ChargeEnergy_DCsideToBattery:Battery_Total_DC_ChargeEnergy_DCsideToBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_DC_ChargeEnergy_DCsideToBattery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Battery_Total_DC_DischargeEnergy_DCsideFromBattery:Battery_Total_DC_DischargeEnergy_DCsideFromBattery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_AC_Energy_ACsideToGrid:Total_AC_Energy_ACsideToGrid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_AC_Energy_ACsideToGrid&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_AC_Energy_ACsideToGrid&amp;quot;,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Total_DC_Energy_From_PV1:Total_DC_Energy_From_PV1.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV1&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV2:Total_DC_Energy_From_PV2.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV2&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV3:Total_DC_Energy_From_PV3.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_Energy_From_PV3&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV4:Total_DC_Energy_From_PV1.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV1&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV5:Total_DC_Energy_From_PV2.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV2&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_Energy_From_PV6:Total_DC_Energy_From_PV3.* monotonic { round(ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_Energy_From_PV3&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_DC_PV_Energy_sumOfAllPVInputs:Total_DC_PV_Energy_sumOfAllPVInputs.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_DC_PV_Energy_sumOfAllPVInputs&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Total_DC_PV_Energy_sumOfAllPVInputs&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_Battery:Total_home_consumption_Battery.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_Battery&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_Grid:Total_home_consumption_Grid.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_Grid&amp;quot;,0),0) },\&lt;br /&gt;
SW_Total_home_consumption_PV:Total_home_consumption_PV.* monotonic { round(ReadingsVal($NAME,&amp;quot;Total_home_consumption_PV&amp;quot;,0),0) }&lt;br /&gt;
attr WR_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======userReadings======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userReadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind.&lt;br /&gt;
&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_Battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_Battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_Battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
SW_*&lt;br /&gt;
   Bei mehreren Wechselrichtern werden einige Werte vom Plenticore fehlerhaft ermittelt und durch diese readings korrigiert.&lt;br /&gt;
   Wann Kostal das in der Firmware korrigiert ist nicht bekannt.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition WR_2 Slave (bei zwei Wechselrichtern)======&lt;br /&gt;
In einem Schwarm kann man den zweiten Wechselrichter etwas sparsamer definieren, da es nur einen Wechselrichter mit Speicher geben darf und der zweite Wechselrichter auch keine KSEM Verbindung hat. Auch die SW_* readings werden hier nicht benötigt. Im userReading des WR_1 und WR_1_API wird auch auf den WR_2 und WR_2_API referenziert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2 ModbusAttr 71 60 &amp;lt;Ip-Adresse&amp;gt;:1502 TCP&lt;br /&gt;
attr WR_2 DbLogExclude .*&lt;br /&gt;
attr WR_2 DbLogInclude P_DC1,P_DC2,P_DC3,Total_DC_P.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_2 alias WR_2&lt;br /&gt;
attr WR_2 alignTime 00:00&lt;br /&gt;
attr WR_2 comment Version 2021.06.02 14:00\&lt;br /&gt;
Kostal Plenticore Plus 7&lt;br /&gt;
attr WR_2 dev-h-combine 8&lt;br /&gt;
attr WR_2 dev-h-defFormat %.2f&lt;br /&gt;
attr WR_2 dev-h-defLen 2&lt;br /&gt;
attr WR_2 dev-h-defPoll 1&lt;br /&gt;
attr WR_2 dev-h-defRevRegs 1&lt;br /&gt;
attr WR_2 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr WR_2 dev-type-STR-format %s&lt;br /&gt;
attr WR_2 dev-type-STR-len 8&lt;br /&gt;
attr WR_2 dev-type-STR-revRegs 0&lt;br /&gt;
attr WR_2 dev-type-STR-unpack a*&lt;br /&gt;
attr WR_2 disable 0&lt;br /&gt;
attr WR_2 event-on-change-reading P_DC1,P_DC2,P_DC3,Total_DC_P.*,Total_DC_PV_Energy.*,Total_AC_Active_P.*,Inverter_state.*,Inverter_Generation_P_Actual.*,P_limit_from_EVU.*&lt;br /&gt;
attr WR_2 group PV Eigenverbrauch&lt;br /&gt;
attr WR_2 icon sani_solar&lt;br /&gt;
attr WR_2 obj-h100-reading Total_DC_P&lt;br /&gt;
attr WR_2 obj-h1058-reading Total_DC_Energy_From_PV1&lt;br /&gt;
attr WR_2 obj-h1060-reading Total_DC_Energy_From_PV2&lt;br /&gt;
attr WR_2 obj-h1062-reading Total_DC_Energy_From_PV3&lt;br /&gt;
attr WR_2 obj-h1064-reading Total_AC_Energy_ACsideToGrid&lt;br /&gt;
attr WR_2 obj-h1066-reading Total_DC_P_sumOfAllPVInputs&lt;br /&gt;
attr WR_2 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr WR_2 obj-h122-reading P_limit_from_EVU&lt;br /&gt;
attr WR_2 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr WR_2 obj-h14-type STR&lt;br /&gt;
attr WR_2 obj-h144-reading Worktime&lt;br /&gt;
attr WR_2 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr WR_2 obj-h152-reading Grid_frequency&lt;br /&gt;
attr WR_2 obj-h154-reading I_L1&lt;br /&gt;
attr WR_2 obj-h156-reading Active_P_L1&lt;br /&gt;
attr WR_2 obj-h158-reading U_L1&lt;br /&gt;
attr WR_2 obj-h160-reading I_L2&lt;br /&gt;
attr WR_2 obj-h162-reading Active_P_L2&lt;br /&gt;
attr WR_2 obj-h164-reading U_L2&lt;br /&gt;
attr WR_2 obj-h166-reading I_L3&lt;br /&gt;
attr WR_2 obj-h168-reading Active_P_L3&lt;br /&gt;
attr WR_2 obj-h170-reading U_L3&lt;br /&gt;
attr WR_2 obj-h172-reading Total_AC_Active_P&lt;br /&gt;
attr WR_2 obj-h174-reading Total_AC_Reactive_P&lt;br /&gt;
attr WR_2 obj-h178-reading Total_AC_Apparent_P&lt;br /&gt;
attr WR_2 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr WR_2 obj-h254-reading Total_Reactive_P_EM&lt;br /&gt;
attr WR_2 obj-h258-reading I_DC1&lt;br /&gt;
attr WR_2 obj-h260-reading P_DC1&lt;br /&gt;
attr WR_2 obj-h266-reading U_DC1&lt;br /&gt;
attr WR_2 obj-h268-reading I_DC2&lt;br /&gt;
attr WR_2 obj-h270-reading P_DC2&lt;br /&gt;
attr WR_2 obj-h276-reading U_DC2&lt;br /&gt;
attr WR_2 obj-h278-reading I_DC3&lt;br /&gt;
attr WR_2 obj-h280-reading P_DC3&lt;br /&gt;
attr WR_2 obj-h286-reading U_DC3&lt;br /&gt;
attr WR_2 obj-h320-reading Total_yield&lt;br /&gt;
attr WR_2 obj-h322-reading Daily_yield&lt;br /&gt;
attr WR_2 obj-h324-reading Yearly_yield&lt;br /&gt;
attr WR_2 obj-h326-reading Monthly_yield&lt;br /&gt;
attr WR_2 obj-h38-reading Software-Version_Maincontroller_MC&lt;br /&gt;
attr WR_2 obj-h38-type STR&lt;br /&gt;
attr WR_2 obj-h384-len 16&lt;br /&gt;
attr WR_2 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr WR_2 obj-h384-type STR&lt;br /&gt;
attr WR_2 obj-h420-reading IP-address&lt;br /&gt;
attr WR_2 obj-h420-type STR&lt;br /&gt;
attr WR_2 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr WR_2 obj-h428-type STR&lt;br /&gt;
attr WR_2 obj-h436-reading IP-gateway&lt;br /&gt;
attr WR_2 obj-h436-type STR&lt;br /&gt;
attr WR_2 obj-h446-reading IP-DNS1&lt;br /&gt;
attr WR_2 obj-h446-type STR&lt;br /&gt;
attr WR_2 obj-h454-reading IP-DNS2&lt;br /&gt;
attr WR_2 obj-h454-type STR&lt;br /&gt;
attr WR_2 obj-h46-reading Software-Version_IO-Controller_IOC&lt;br /&gt;
attr WR_2 obj-h46-type STR&lt;br /&gt;
attr WR_2 obj-h529-len 4&lt;br /&gt;
attr WR_2 obj-h529-reading Work_Capacity&lt;br /&gt;
attr WR_2 obj-h529-unpack N&lt;br /&gt;
attr WR_2 obj-h531-format %.0f&lt;br /&gt;
attr WR_2 obj-h531-reading Inverter_Max_P&lt;br /&gt;
attr WR_2 obj-h531-unpack N&lt;br /&gt;
attr WR_2 obj-h535-revRegs 0&lt;br /&gt;
attr WR_2 obj-h535-unpack n&lt;br /&gt;
attr WR_2 obj-h551-revRegs 0&lt;br /&gt;
attr WR_2 obj-h559-revRegs 0&lt;br /&gt;
attr WR_2 obj-h56-format %.0f&lt;br /&gt;
attr WR_2 obj-h56-reading Inverter_state&lt;br /&gt;
attr WR_2 obj-h56-unpack N&lt;br /&gt;
attr WR_2 obj-h575-reading Inverter_Generation_P_Actual&lt;br /&gt;
attr WR_2 obj-h575-unpack N&lt;br /&gt;
attr WR_2 obj-h577-len 2&lt;br /&gt;
attr WR_2 obj-h577-reading Generation_Energy&lt;br /&gt;
attr WR_2 obj-h577-unpack N&lt;br /&gt;
attr WR_2 obj-h578-reading Total_energy&lt;br /&gt;
attr WR_2 obj-h6-reading Inverter_Article_number&lt;br /&gt;
attr WR_2 obj-h6-type STR&lt;br /&gt;
attr WR_2 obj-h768-len 32&lt;br /&gt;
attr WR_2 obj-h768-reading Productname&lt;br /&gt;
attr WR_2 obj-h768-type STR&lt;br /&gt;
attr WR_2 obj-h800-len 32&lt;br /&gt;
attr WR_2 obj-h800-reading Power_class&lt;br /&gt;
attr WR_2 obj-h800-type STR&lt;br /&gt;
attr WR_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2 sortby 211&lt;br /&gt;
attr WR_2 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Kostal Plenticore Plus die API=====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Auch hier werden bei mehreren AC-Quellen falsche Werte ausgegeben, die durch SW_* userReadings korrigiert wurden.&lt;br /&gt;
&lt;br /&gt;
======Plenticore API======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Plenticore Testablauf======&lt;br /&gt;
Für die erste Implementierung ist es zu empfehlen alle Devices so zu belassen und zu benennen, wie sie im Wiki angegeben sind.&lt;br /&gt;
Eine persönliche Anpassung ist erst sinnvoll, wenn alles läuft, da hierdurch bereits schon im Vorfeld viele Fehler verursacht wurden, die eine Unterstützung erschweren.&lt;br /&gt;
&lt;br /&gt;
Folgendes bitte aktivieren, damit genügend Meldungen zusehen sind&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global verbose 3&lt;br /&gt;
attr &amp;lt;device&amp;gt; verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bitte unbedingt bei Problemen den Log Ausschnitt mit senden und die Meldungen anderer Devices vorher herauslöschen, da es ansonsten schwierig ist eine Diagnose zu betreiben. &lt;br /&gt;
Tests sind bei den einzelnen Schritten direkt mit angegeben.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() und KeyValue() Voraussetzung======&lt;br /&gt;
Diese Einträge müssen, falls noch nicht vorhanden in die 99_myUtils eingetragen werden. Hierdurch lädt man zusätzliche, nicht Standardfunktionen aus Perl Bibliotheken in ein Modul.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* use Encode qw(decode encode);&lt;br /&gt;
* use PBKDF2::Tiny qw/derive verify/;&lt;br /&gt;
* use Digest::SHA qw(sha256 hmac_sha256);&lt;br /&gt;
* use Crypt::URandom qw( urandom );&lt;br /&gt;
* use Crypt::AuthEnc::GCM;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Je nach dem welche Installation Ihr verwendet kann es auch sein, dass noch weitere Module installiert werden müssen. Es wurde bereits folgendes gemeldet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
* sudo apt-get install libcryptx-perl&lt;br /&gt;
* sudo apt-get install libpbkdf2-tiny-perl&lt;br /&gt;
* sudo apt-get install libcrypt-urandom-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Erläuterung Passworte======&lt;br /&gt;
Das Passwort für den Plenticore wird mit der Funktion KeyValue() im KeyStore vom FHEM abgelegt und ausgelesen. &#039;&#039;&#039;Bitte beachtet, dass dies kein Schutz gegen das Stehlen von Passworten ist.&#039;&#039;&#039; Es dient lediglich der Ablage von Keys, damit sie nicht direkt offen im Datensystem oder im Konfigurationsfile zu finden sind.&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils .&lt;br /&gt;
&lt;br /&gt;
======KeyValue()======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub KeyValue {&lt;br /&gt;
    my ($step, $index, $value) = @_;&lt;br /&gt;
    my $key = getUniqueId().$index;&lt;br /&gt;
    my $e_value = &amp;quot;&amp;quot;;&lt;br /&gt;
    my $error;&lt;br /&gt;
&lt;br /&gt;
    if (eval &amp;quot;use Digest::MD5;1&amp;quot;) {&lt;br /&gt;
      $key    = Digest::MD5::md5_hex(unpack &amp;quot;H*&amp;quot;, $key);&lt;br /&gt;
      $key   .= Digest::MD5::md5_hex($key);&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    if ($step eq &amp;quot;read&amp;quot;) {&lt;br /&gt;
      ($error, $value) = getKeyValue($index);&lt;br /&gt;
&lt;br /&gt;
      if ( defined($error) ) {&lt;br /&gt;
        Log3 $index,3, &amp;quot;$index, can&#039;t read key from FhemUtils/uniqueID: $error&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ( defined($value) ) {&lt;br /&gt;
        my $dec_value = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
        for my $char (map { pack(&#039;C&#039;, hex($_)) } ($value =~ /(..)/g)) {&lt;br /&gt;
          my $decode  = chop($key);&lt;br /&gt;
          $dec_value .= chr(ord($char)^ord($decode));&lt;br /&gt;
          $key        = $decode.$key;&lt;br /&gt;
        }&lt;br /&gt;
        return $dec_value;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        Log3 $index,3,&amp;quot;$index, no key found in FhemUtils/uniqueID&amp;quot;;&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($step eq &amp;quot;store&amp;quot;) {&lt;br /&gt;
      for my $char (split //, $value) {&lt;br /&gt;
        my $encode = chop($key);&lt;br /&gt;
        $e_value  .= sprintf(&amp;quot;%.2x&amp;quot;,ord($char)^ord($encode));&lt;br /&gt;
        $key       = $encode.$key;&lt;br /&gt;
      }&lt;br /&gt;
      $error = setKeyValue($index, $e_value);&lt;br /&gt;
      return &amp;quot;error while saving key : $error&amp;quot; if(defined($error));&lt;br /&gt;
      return &amp;quot;Key successfully saved in FhemUtils/uniqueID Key $index&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======KeyValue() Test======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline von FHEM aufgerufen werden.&lt;br /&gt;
Der Syntax von &amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot; ist so beizubehalten. &#039;&#039;&#039;Beim Umbenennen der WR_1_API Device ist hier dann auch das Passwort neu im KeyStore abzulegen.&#039;&#039;&#039;&lt;br /&gt;
Der Key &amp;quot;user&amp;quot; ist die Benutzerkennung des &amp;quot;Anlagenbetreibers&amp;quot; im Plenticore. Bei der Anmeldung am Plenticore Web Interface wird &amp;quot;Anlagenbetreiber&amp;quot; ausgewählt, jedoch wird dies im Hintergrund auf den Benutzernamen &amp;quot;user&amp;quot; gemapped. &#039;&#039;&#039;Somit ist für die API &amp;quot;user&amp;quot; zu verwenden und das Passwort des Anlagenbetreibers vom Web-GUI&#039;&#039;&#039;. Oft entspricht das Passwort des Anlagenbetreibers dem &amp;quot;Master Key&amp;quot; der sich auf dem Aufkleber des Plenticore befindet. Sollte das nicht der Fall sein, so kann man auch das Passwort auf den &amp;quot;Master Key&amp;quot; zurück setzen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Wenn das Passwort aus dem KeyStore mit read abgeholt wird, wird es im Klartext angezeigt!&#039;&#039;&#039; Dies muss einzeilig und identisch zum Passwort des Anlagenbetreibers vom Web-GUI erscheinen. Bei etwaigen Sonderzeichen kam es hier schon zu Abweichungen. In solch einem Fall muss man dann leider das Passwort des Anlagenbetreibers vom Web-GUI im Plenticore ändern.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Erläuterung======&lt;br /&gt;
Diese Funktion befindet sich in der 99_myUtils und dient der Erstellung von Keys für die mehrstufige Anmeldung des Kostal Plenticore Plus.&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth()======&lt;br /&gt;
Für die Abfrage des KeyValue gab es hier direkt am Anfang der Funktion eine Änderung (2021.04.07). Auch das Logging wurde verändert und kann nun durch das Setzen von &amp;quot;attr WR_1_API verbose 5&amp;quot; aktiviert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub plenticore_auth {&lt;br /&gt;
   my ($step, $user, $logdevice, $randomString, $nonce, $salt, $rounds, $transactionId, $token) = @_;&lt;br /&gt;
&lt;br /&gt;
   my $verbose     = AttrVal($logdevice,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
   my $PASSWD = KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_&amp;quot;.$logdevice.&amp;quot;_&amp;quot;.$user);&lt;br /&gt;
&lt;br /&gt;
   if ($verbose &amp;gt;= 3) {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====Start plenticore_auth==============================&amp;quot;;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_step         : &amp;quot;.$step;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_user         : &amp;quot;.$user;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_device       : &amp;quot;.$logdevice;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_KeyValue read: PW_&amp;quot;.$logdevice.&amp;quot;_&amp;quot;.$user;&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   if($step eq &amp;quot;start&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     my @chars = (&#039;0&#039;..&#039;9&#039;, &#039;A&#039;..&#039;Z&#039;, &#039;a&#039;..&#039;z&#039;);&lt;br /&gt;
     my $len = 12;&lt;br /&gt;
     my $string;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     while($len--){ $string .= $chars[rand @chars] };&lt;br /&gt;
     $string = encode(&amp;quot;UTF-8&amp;quot;, $string);&lt;br /&gt;
     $string = decode(&amp;quot;UTF-8&amp;quot;, $string);&lt;br /&gt;
     my $u = encode_base64($string);&lt;br /&gt;
     $u =~ s/\n$//g;&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;nonce&amp;quot;: &amp;quot;&#039;.$u.&#039;&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;&#039;.$user.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_nonce        : &amp;quot;.$u;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
     &lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; auth_randomString64 &amp;quot;.$u) ;&lt;br /&gt;
 &lt;br /&gt;
    return $message;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
   ######### This code is identical for finish and session #################&lt;br /&gt;
   my $bitSalt = decode_base64($salt);&lt;br /&gt;
   my $r = derive( &#039;SHA-256&#039;, $PASSWD, $bitSalt, $rounds );&lt;br /&gt;
   my $ck = encode(&#039;UTF-8&#039;, &amp;quot;Client Key&amp;quot;);&lt;br /&gt;
   my $s = hmac_sha256($ck, $r);&lt;br /&gt;
   my $underscore = sha256($s);&lt;br /&gt;
   my $d = &amp;quot;n=&amp;quot;.$user.&amp;quot;,r=&amp;quot;.$randomString.&amp;quot;,r=&amp;quot;.$nonce.&amp;quot;,s=&amp;quot;.$salt.&amp;quot;,i=&amp;quot;.$rounds.&amp;quot;,c=biws,r=&amp;quot;.$nonce;&lt;br /&gt;
&lt;br /&gt;
   if ($verbose &amp;gt;= 3) {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_randomString : &amp;quot;.$randomString;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_nonce        : &amp;quot;.$nonce;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_salt         : &amp;quot;.$salt;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_rounds       : &amp;quot;.$rounds;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_transactionId: &amp;quot;.$transactionId;&lt;br /&gt;
   };&lt;br /&gt;
   &lt;br /&gt;
   if($step eq &amp;quot;finish&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
     my $sk = encode(&#039;UTF-8&#039;, &amp;quot;Server Key&amp;quot;);&lt;br /&gt;
     my $c = hmac_sha256($sk, $r);&lt;br /&gt;
     my $pd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $p = hmac_sha256($pd, $c);&lt;br /&gt;
     my $gd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $g = hmac_sha256($gd, $underscore);&lt;br /&gt;
     my $f = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $g1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $s1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $f1 = &amp;quot;&amp;quot;;&lt;br /&gt;
     my $j = 0;&lt;br /&gt;
     for($j=0; $j&amp;lt;length($g); $j++) {&lt;br /&gt;
        $g1 = substr($g,$j,1);&lt;br /&gt;
        $s1 = substr($s,$j,1);&lt;br /&gt;
        $f1 = $s1 ^ $g1 ;&lt;br /&gt;
        $f = $f.$f1;&lt;br /&gt;
     }&lt;br /&gt;
     my $pe = encode_base64($f);&lt;br /&gt;
     $pe =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $proof = decode(&#039;UTF-8&#039;, $pe);&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;transactionId&amp;quot;: &amp;quot;&#039;.$transactionId.&#039;&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;&#039;.$proof.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_proof        : &amp;quot;.$proof;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     return $message;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
   if($step eq &amp;quot;session&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;auth_token        : &amp;quot;.$token;&lt;br /&gt;
     Log3 $logdevice,3,&amp;quot;====End arguments======================================&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
     my $sk = encode(&#039;UTF-8&#039;, &amp;quot;Session Key&amp;quot;);&lt;br /&gt;
     my $dd = encode(&#039;UTF-8&#039;, $d);&lt;br /&gt;
     my $protocol_key = hmac_sha256($sk, $dd, $s, $underscore);&lt;br /&gt;
&lt;br /&gt;
     my $t = &amp;quot;7244ba6f73c8cdc47b232e1311451939&amp;quot;;&lt;br /&gt;
     $t =~ s/([a-fA-F0-9][a-fA-F0-9])/chr(hex($1))/eg;&lt;br /&gt;
     my $e2 = Crypt::AuthEnc::GCM-&amp;gt;new(&amp;quot;AES&amp;quot;, $protocol_key, $t);&lt;br /&gt;
     my $tt = encode(&#039;UTF-8&#039;, $token);&lt;br /&gt;
     my $e2ct = $e2-&amp;gt;encrypt_add($tt);&lt;br /&gt;
     my $authtag = $e2-&amp;gt;encrypt_done();&lt;br /&gt;
&lt;br /&gt;
     $tt = encode_base64($t);&lt;br /&gt;
     $tt =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $iv = decode(&#039;UTF-8&#039;, $tt);&lt;br /&gt;
&lt;br /&gt;
     my $aa = encode_base64($authtag);&lt;br /&gt;
     $aa =~ s/\n$//g;                        # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     $authtag = decode(&#039;UTF-8&#039;, $aa);&lt;br /&gt;
&lt;br /&gt;
     my $pp = encode_base64($e2ct);&lt;br /&gt;
     $pp =~ s/\n//g;                         # Korrektur: \n am Ende des Strings entfernen, Ursache unbekannt&lt;br /&gt;
     my $payload = decode(&#039;UTF-8&#039;, $pp);&lt;br /&gt;
&lt;br /&gt;
     my $message = &#039;{&amp;quot;transactionId&amp;quot;: &amp;quot;&#039;.$transactionId.&#039;&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;&#039;.$iv.&#039;&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;&#039;.$authtag.&#039;&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;&#039;.$payload.&#039;&amp;quot;}&#039;;&lt;br /&gt;
&lt;br /&gt;
     if ($verbose &amp;gt;= 3) {&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_iv           : &amp;quot;.$iv;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_authtag      : &amp;quot;.$authtag;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_payload      : &amp;quot;.$payload;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;auth_return       : &amp;quot;.$message;&lt;br /&gt;
       Log3 $logdevice,3,&amp;quot;====End output=========================================&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
     &lt;br /&gt;
     return $message;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======plenticore_auth() Test======&lt;br /&gt;
Nachdem vorher bereits mit KeyValue() das Passwort hinterlegt und getestet wurde kann man die Funktion bereits überprüfen.&lt;br /&gt;
Die Anzahl der Argumente ist je nach gewünschter Funktionalität (start|finish|session) unterschiedlich.&lt;br /&gt;
Da die auth_* Keys zur Laufzeit im Dialog mit dem Plenticore erstellt und ausgetauscht werden, wird hier für den Test mit Beispielwerten gearbeitet&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM:&lt;br /&gt;
{plenticore_auth(&amp;quot;[start|finish|session]&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;&amp;lt;device&amp;gt;&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;auth_token&amp;quot;)}&lt;br /&gt;
Test 1)&lt;br /&gt;
{plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;)}       # Im Hintergrund wird das Passwort aus dem KeyStore verwendet&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;nonce&amp;quot;: &amp;quot;UUZ1dWNEZnowVzh2&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 2)&lt;br /&gt;
{plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;5xZeOxoyR0hzPCVqvD/BPMqscQbT57wSONl049xiLjE=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
Test 3)&lt;br /&gt;
{plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,&amp;quot;TESMUWZnwkJZbnpF&amp;quot;,&amp;quot;TE2MUWZnwkJZbnpFQ5ulCfolNNdAD0vT&amp;quot;,&amp;quot;DbAC0R85jwF0rh+r&amp;quot;,&amp;quot;29000&amp;quot;,&amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;,&amp;quot;acafc66c0e1975293d35512a1e4bcceea55840b3109a703514e75b5ebce9b7c5&amp;quot;)}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; {&amp;quot;transactionId&amp;quot;: &amp;quot;1376720346bea40cdf770a8f84b5975cfeb20c5e6ac6d89b7862df3ca9695e43&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;ckS6b3PIzcR7Iy4TEUUZOQ==&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;ROTpRrav38sLdt3EEuE3tQ==&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;nWraowAhLQVk5RCq8WOo8ZhGvUyHLMNxA13/21w7DuHDqq2LOQRXM143kJE5WNJQgeuoKeLiRunPaRpiJUzK3g==&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Ablaufbeschreibung WR_1_API======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden. Die mehrstufige Anmeldung wird vom HTTPMOD Modul über sid01 bis sid03 abgebildet. Die Keys werden dabei zwischen den Devices ausgetauscht und mit replacements in das HTML eingefügt. Das replacement ruft dafür noch die Funktion plenticore_auth() aus der 99_myUtils auf.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit einer beliebigen Abfrage und läuft dann vollautomatisch bis zur Ausführung des eigentlichen Aufrufes durch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. get WR_1_API 20_Statistic_EnergyFlow&lt;br /&gt;
  2. Sollte noch keine Session aufgebaut sein erfolgt der Aufruf von sid01&lt;br /&gt;
  3. Das Replacement %START% führt plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;) aus&lt;br /&gt;
  4. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  5. Das Replacement %FINISH% führt plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...) aus&lt;br /&gt;
  6. Die Rückmeldung vom Plenticore wird gelesen&lt;br /&gt;
  7. Das Replacement %SESSION% führt plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;WR_1_API&amp;quot;,...,...) aus&lt;br /&gt;
  8. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
  9. Der eigentliche Aufruf wird ausgeführt und die readings bereit gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Anmeldung kann auch teil automatisch erfolgen, was bei etwaigen Fehlern in der Anmeldung nützlich ist. Hier sind nur die manuellen Schritte beschrieben, der Ablauf ist identisch zur vorherigen Beschreibung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   1. get WR_1_API 01_auth_start&lt;br /&gt;
   2. get WR_1_API 02_auth_finish&lt;br /&gt;
   3. get WR_1_API 03_auth_create_session&lt;br /&gt;
   4. Die Rückmeldung vom Plenticore wird gelesen und es sollte eine SessionId bestehen, mit der nun alle weiteren Abfragen laufen&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Implementierte Abfragen======&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch ein Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Login Funktionalität für eine manuelle Anmeldung&lt;br /&gt;
01_auth_start&lt;br /&gt;
02_auth_finish&lt;br /&gt;
03_auth_create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand&lt;br /&gt;
04_auth_me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
05_info_version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
20_Statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Informationen zum Speicher, die auch teilweise gesetzt werden können. Siehe &#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
21_Battery_Information&lt;br /&gt;
22_Battery_InternControl&lt;br /&gt;
23_Battery_ExternControl&lt;br /&gt;
24_Battery_TimeControl&lt;br /&gt;
25_Battery_EM_State&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit &amp;quot;showBody&amp;quot; angezeigt werden kann. Es erfolgt keine Umsetzung des JSON in readings.&lt;br /&gt;
attr &amp;lt;Device&amp;gt; showBody 1&lt;br /&gt;
51_modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
attr &amp;lt;Device&amp;gt; timeout 7&lt;br /&gt;
59_logdata_download&lt;br /&gt;
&lt;br /&gt;
Das zeigt den Firmware Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
60_update_status&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;set:&#039;&#039;&#039;&lt;br /&gt;
Bei den set Aufrufen ist automatisch ein get Aufruf im Anschluss gekoppelt, wodurch der neue Zustand wieder abgefragt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eine bestehende Session wird abgemeldet, als Rückmeldung erscheint im httpbody nur ein &amp;quot;null&amp;quot;&lt;br /&gt;
06_auth_logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
23_events latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
22_03_Battery_MinHomeConsumption&lt;br /&gt;
22_04_Battery_MinSoc&lt;br /&gt;
22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
22_06_Battery_Strategy&lt;br /&gt;
22_07_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
23_00_Battery_ExternControl&lt;br /&gt;
23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
&lt;br /&gt;
Hier kann eine Lister der letzten 5 Events abgeholt werden. Achtung lange Laufzeit, da immer die gesamte Liste abgerufen wird und dort sehr viele Einträge sind.&lt;br /&gt;
50_events_latest_5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_1_API Master ab v1.16======&lt;br /&gt;
Achtung, wenn Ihr zu dieser Definition wechselt, haben sich die get/set Bezeichnungen geändert. Bitte korrigiert dann auch das PV_Schedule Device entsprechend.&lt;br /&gt;
Beim Wechsel auf die v1.16 sind diverse Batterie Funktionalitäten hinzu gekommen, die man jedoch vom Installateur aktivieren lassen muss. Bitte denkt daran, dass der Installateur für jeden Wechsel der Batterie Konfiguration von intern auf extern und zurück, zu Euch kommen muss!&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Settings für die Batterie ist nun in intern/extern gruppiert und es werden dann mehrere Settings gleichzeitig abgefragt. &#039;&#039;&#039;Beim Setzen hingegen erfolgt jedes Setting einzeln und das erfolgreiche Setzen ist am Ende mit einem erneuten get zu überprüfen.&#039;&#039;&#039; Stand 2021.04.07 im HTTPMOD wird ein Attribut set[*]FollowGet unterstützt, wodurch nun ein automatisches get nach dem set erfolgt. Dies vereinfacht das Timing, da das set bereits komplett erledigt wurde, bevor der Status neu abgefragt wird.&lt;br /&gt;
&lt;br /&gt;
Die Nummerierung beim get/set soll die Zusammenhänge etwas klarer machen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get 21_Battery_InternControl&lt;br /&gt;
set 21_04_Battery_MinSoc (mit automatischem FollowGet)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung, Voraussetzung ist mindestens die HTTPMOD Version 4.1.00&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Auch dieses Device ist für den Betrieb mehrerer Wechselrichter vorbereitet. Hierbei sollte der erste WR_1 und der zweite WR_2 benannt werden. Beim Betrieb nur eines Wechselrichters werden die userReadings SW_* ebenfalls befüllt und beinhalten die Werte des ersten Wechselrichters. Somit ist ein Betrieb in beiden Umgebungen möglich. Beim Logging muss man sich entscheiden und DbLogInclude entsprechend setzen, damit die Werte nicht doppelt ins DbLog geschrieben werden. Achtung, dies hat auch Auswirkungen auf die Diagramme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für die Korrektur der Statistiken werden die Stromzähler Stände des KSEM benötigt&#039;&#039;&#039;, die als reading mit Active_energy[+|-] bezeichnet sind. Bisher war es nicht erforderlich den KSEM im FHEM per ModBus abzufragen, was jedoch nun notwendig ist. In dieser Integration wurde der KSEM wegen des Schwarms auf WR_0_KSEM benannt. Im Device PV_Schedule wurde ein cmd_5 eingefügt, dass die Zählerstände zum Beginn einer Statistikperiode, Day/Month/Year in das Device WR_1_API überträgt. Initial müssen diese manuell korrekt gesetzt werden, damit die Berechnungen in den userReadings stimmen!&lt;br /&gt;
Die Definition des KSEM kommt etwas später im Kapitel [[Kostal_Plenticore_10_Plus#Kostal_Smart_Energy_Manager_.28KSEM.29_.28Modbus.2FTCP.29|Kostal_Smart_Energy_Manager_KSEM_Modbus_TCP]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sollte der Plenticore mal wegen eines Defektes ausgetauscht werden müssen&#039;&#039;&#039;, dann beginnt der neue Wechselrichter seine Statistiken wieder bei Null, was natürlich nicht so schön ist. Für die Tages Statistiken *_Day ist das nicht so tragisch, bei Monat und Jahr stört das schon einwenig. Um das dann kontinuierlich hin zu bekommen muss man aus der Datenbank die letzten gültigen Werte heraussuchen und diese manuell im userreading mit einrechnen. Zum Ende des Monats bzw. des Jahres sind dann die Offsets wieder heraus zu nehmen und gegebenenfalls nochmals in der Datenbank zu prüfen.&lt;br /&gt;
Betroffen sind die folgenden SW_* userreadings, die hier mit exemplarischen Zahlenwerten korrigiert werden.&lt;br /&gt;
Am besten macht Ihr Euch zum Ende der Periode einen Eintrag im Kalender, damit Ihr die Korrektur rechtzeitig wieder raus nehmt.&lt;br /&gt;
&#039;&#039;&#039;Bei allen anderen userreadings wurde ein solcher Wechsel bereits berücksichtigt und schreibt die Werte mit Hilfe der monotonik Funktion kontinuierlich weiter.&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0) + 195000},&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0) + 772000},&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) - 42000 },&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0),0) - 158000 },&lt;br /&gt;
&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0) + 42000},&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* { round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) +ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0) + 158000},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RAW Definition des WR_1_API Master ab v1.16&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_1_API userattr get25-1Name get25JSON get25Regex&lt;br /&gt;
attr WR_1_API DbLogExclude .*&lt;br /&gt;
attr WR_1_API DbLogInclude Statistic_Autarky.*,Statistic_Energy.*,Statistic_Own.*,Statistic_Total.*,Statistic_Yield.*,SW_.*&lt;br /&gt;
attr WR_1_API authRetries 1&lt;br /&gt;
attr WR_1_API comment Version 2022.03.29 09:00\&lt;br /&gt;
Passworte für die Abfrage des WR_1_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_1_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_1_API disable 0&lt;br /&gt;
attr WR_1_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_API enableControlSet 0&lt;br /&gt;
attr WR_1_API enableCookies 1&lt;br /&gt;
attr WR_1_API event-on-change-reading Battery_.*&lt;br /&gt;
attr WR_1_API event-on-update-reading auth_.*,Statistic_Autarky.*,Statistic_EnergyFeedIn.*,Statistic_EnergyHome.*,Statistic_EnergyPv[1|2].*,Statistic_.*Consumption.*,Statistic_Energy.*_Total,Statistic_Yield.*,SW_.*&lt;br /&gt;
attr WR_1_API get01Data %START%&lt;br /&gt;
attr WR_1_API get01Name 01_auth_start&lt;br /&gt;
attr WR_1_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_1_API get02Data %FINISH%&lt;br /&gt;
attr WR_1_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_1_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_1_API get03Data %SESSION%&lt;br /&gt;
attr WR_1_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_1_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_1_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_1_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_1_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_1_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_1_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_1_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get04JSON .&lt;br /&gt;
attr WR_1_API get04Name 04_auth_me&lt;br /&gt;
attr WR_1_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_1_API get05-1Name info_api_version&lt;br /&gt;
attr WR_1_API get05-2Name info_hostname&lt;br /&gt;
attr WR_1_API get05-3Name info_name&lt;br /&gt;
attr WR_1_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_1_API get05JSON .&lt;br /&gt;
attr WR_1_API get05Name 05_info_version&lt;br /&gt;
attr WR_1_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_1_API get20-10Format %.2f&lt;br /&gt;
attr WR_1_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_1_API get20-11Format %.2f&lt;br /&gt;
attr WR_1_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_1_API get20-12Format %.2f&lt;br /&gt;
attr WR_1_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_1_API get20-13Format %.2f&lt;br /&gt;
attr WR_1_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_1_API get20-14Format %.2f&lt;br /&gt;
attr WR_1_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_1_API get20-15Format %.2f&lt;br /&gt;
attr WR_1_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_1_API get20-16Format %.2f&lt;br /&gt;
attr WR_1_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_1_API get20-17Format %.2f&lt;br /&gt;
attr WR_1_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_1_API get20-18Format %.2f&lt;br /&gt;
attr WR_1_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_1_API get20-19Format %.2f&lt;br /&gt;
attr WR_1_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_1_API get20-1Format %.2f&lt;br /&gt;
attr WR_1_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_1_API get20-20Format %.2f&lt;br /&gt;
attr WR_1_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_1_API get20-21Format %.2f&lt;br /&gt;
attr WR_1_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_1_API get20-22Format %.2f&lt;br /&gt;
attr WR_1_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_1_API get20-23Format %.2f&lt;br /&gt;
attr WR_1_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_1_API get20-24Format %.2f&lt;br /&gt;
attr WR_1_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_1_API get20-25Format %.2f&lt;br /&gt;
attr WR_1_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_1_API get20-26Format %.2f&lt;br /&gt;
attr WR_1_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_1_API get20-27Format %.2f&lt;br /&gt;
attr WR_1_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_1_API get20-28Format %.2f&lt;br /&gt;
attr WR_1_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_1_API get20-29Format %.2f&lt;br /&gt;
attr WR_1_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_1_API get20-2Format %.2f&lt;br /&gt;
attr WR_1_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_1_API get20-30Format %.2f&lt;br /&gt;
attr WR_1_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_1_API get20-31Format %.2f&lt;br /&gt;
attr WR_1_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_1_API get20-32Format %.2f&lt;br /&gt;
attr WR_1_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_1_API get20-33Format %.2f&lt;br /&gt;
attr WR_1_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_1_API get20-34Format %.2f&lt;br /&gt;
attr WR_1_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_1_API get20-35Format %.2f&lt;br /&gt;
attr WR_1_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_1_API get20-36Format %.2f&lt;br /&gt;
attr WR_1_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_1_API get20-37Format %.2f&lt;br /&gt;
attr WR_1_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_1_API get20-38Format %.2f&lt;br /&gt;
attr WR_1_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_1_API get20-39Format %.2f&lt;br /&gt;
attr WR_1_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_1_API get20-3Format %.2f&lt;br /&gt;
attr WR_1_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_1_API get20-40Format %.2f&lt;br /&gt;
attr WR_1_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_1_API get20-41Format %.2f&lt;br /&gt;
attr WR_1_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_1_API get20-42Format %.2f&lt;br /&gt;
attr WR_1_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_1_API get20-43Format %.2f&lt;br /&gt;
attr WR_1_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_1_API get20-44Format %.2f&lt;br /&gt;
attr WR_1_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_1_API get20-45Format %.2f&lt;br /&gt;
attr WR_1_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_1_API get20-46Format %.2f&lt;br /&gt;
attr WR_1_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_1_API get20-47Format %.2f&lt;br /&gt;
attr WR_1_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_1_API get20-48Format %.2f&lt;br /&gt;
attr WR_1_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_1_API get20-49Format %.2f&lt;br /&gt;
attr WR_1_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_1_API get20-4Format %.2f&lt;br /&gt;
attr WR_1_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_1_API get20-50Format %.2f&lt;br /&gt;
attr WR_1_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_1_API get20-51Format %.2f&lt;br /&gt;
attr WR_1_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_1_API get20-52Format %.2f&lt;br /&gt;
attr WR_1_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_1_API get20-53Format %.2f&lt;br /&gt;
attr WR_1_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_1_API get20-54Format %.2f&lt;br /&gt;
attr WR_1_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_1_API get20-55Format %.2f&lt;br /&gt;
attr WR_1_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_1_API get20-56Format %.2f&lt;br /&gt;
attr WR_1_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_1_API get20-57Format %.2f&lt;br /&gt;
attr WR_1_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_1_API get20-58Format %.2f&lt;br /&gt;
attr WR_1_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_1_API get20-59Format %.2f&lt;br /&gt;
attr WR_1_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_1_API get20-5Format %.2f&lt;br /&gt;
attr WR_1_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_1_API get20-60Format %.2f&lt;br /&gt;
attr WR_1_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_1_API get20-61Format %.2f&lt;br /&gt;
attr WR_1_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_1_API get20-62Format %.2f&lt;br /&gt;
attr WR_1_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_1_API get20-63Format %.2f&lt;br /&gt;
attr WR_1_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_1_API get20-64Format %.2f&lt;br /&gt;
attr WR_1_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_1_API get20-65Format %.2f&lt;br /&gt;
attr WR_1_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_1_API get20-6Format %.2f&lt;br /&gt;
attr WR_1_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_1_API get20-7Format %.2f&lt;br /&gt;
attr WR_1_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_1_API get20-8Format %.2f&lt;br /&gt;
attr WR_1_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_1_API get20-9Format %.2f&lt;br /&gt;
attr WR_1_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_1_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_1_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_1_API get21-1Name Battery_Info_Cycles&lt;br /&gt;
attr WR_1_API get21-2Name Battery_Info_FullChargeCap_E&lt;br /&gt;
attr WR_1_API get21-3Name Battery_Info_SoC&lt;br /&gt;
attr WR_1_API get21-4Format %d&lt;br /&gt;
attr WR_1_API get21-4Name Battery_Info_WorkCapacity&lt;br /&gt;
attr WR_1_API get21Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get21Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get21JSON .._processdata_.._value&lt;br /&gt;
attr WR_1_API get21Name 21_Battery_Information&lt;br /&gt;
attr WR_1_API get21URL http://%IP-WR%/api/v1/processdata/devices:local:battery/Cycles,FullChargeCap_E,SoC,WorkCapacity&lt;br /&gt;
attr WR_1_API get22-1Name Battery_InternControl_DynamicSoc_Enable&lt;br /&gt;
attr WR_1_API get22-2Name Battery_Control&lt;br /&gt;
attr WR_1_API get22-3Format %d&lt;br /&gt;
attr WR_1_API get22-3Name Battery_InternControl_MinHomeConsumption&lt;br /&gt;
attr WR_1_API get22-4Name Battery_InternControl_MinSoc&lt;br /&gt;
attr WR_1_API get22-5Name Battery_InternControl_SmartBatteryControl_Enable&lt;br /&gt;
attr WR_1_API get22-6Name Battery_InternControl_Strategy&lt;br /&gt;
attr WR_1_API get22-7Name Battery_InternControl_Type&lt;br /&gt;
attr WR_1_API get22Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get22Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get22JSON .._value&lt;br /&gt;
attr WR_1_API get22Name 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API get22URL http://%IP-WR%/api/v1/settings/devices:local/Battery:ExternControl,Battery:Type,Battery:MinHomeComsumption,Battery:Strategy,Battery:MinSoc,Battery:SmartBatteryControl:Enable,Battery:DynamicSoc:Enable,Battery:Type&lt;br /&gt;
attr WR_1_API get23-10Format %d&lt;br /&gt;
attr WR_1_API get23-10Name Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
attr WR_1_API get23-11Format %d&lt;br /&gt;
attr WR_1_API get23-11Name Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
attr WR_1_API get23-12Format %d&lt;br /&gt;
attr WR_1_API get23-12Name Battery_ExternControl_MaxSocRel&lt;br /&gt;
attr WR_1_API get23-13Format %d&lt;br /&gt;
attr WR_1_API get23-13Name Battery_ExternControl_MinSocRel&lt;br /&gt;
attr WR_1_API get23-1Name Battery_ComMonitor_Enable&lt;br /&gt;
attr WR_1_API get23-2Format %d&lt;br /&gt;
attr WR_1_API get23-2Name Battery_ComMonitor_Time&lt;br /&gt;
attr WR_1_API get23-3Name Battery_Control&lt;br /&gt;
attr WR_1_API get23-4Format %.2f&lt;br /&gt;
attr WR_1_API get23-4Name Battery_ExternControl_AcPowerAbs&lt;br /&gt;
attr WR_1_API get23-5Format %.2f&lt;br /&gt;
attr WR_1_API get23-5Name Battery_ExternControl_AcPowerRel&lt;br /&gt;
attr WR_1_API get23-6Format %.2f&lt;br /&gt;
attr WR_1_API get23-6Name Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
attr WR_1_API get23-7Format %.2f&lt;br /&gt;
attr WR_1_API get23-7Name Battery_ExternControl_DcCurrentRel&lt;br /&gt;
attr WR_1_API get23-8Format %.2f&lt;br /&gt;
attr WR_1_API get23-8Name Battery_ExternControl_DcPowerAbs&lt;br /&gt;
attr WR_1_API get23-9Format %.2f&lt;br /&gt;
attr WR_1_API get23-9Name Battery_ExternControl_DcPowerRel&lt;br /&gt;
attr WR_1_API get23Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get23Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get23JSON .._value&lt;br /&gt;
attr WR_1_API get23Name 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API get23URL http://%IP-WR%/api/v1/settings/devices:local/Battery:ComMonitor:Enable,Battery:ComMonitor:Time,Battery:ExternControl,Battery:ExternControl:AcPowerAbs,Battery:ExternControl:AcPowerRel,Battery:ExternControl:DcCurrentAbs,Battery:ExternControl:DcCurrentRel,Battery:ExternControl:DcPowerAbs,Battery:ExternControl:DcPowerRel,Battery:ExternControl:MaxChargePowerAbs,Battery:ExternControl:MaxDischargePowerAbs,Battery:ExternControl:MaxSocRel,Battery:ExternControl:MinSocRel&lt;br /&gt;
attr WR_1_API get24-1Name Battery_TimeControl_1&lt;br /&gt;
attr WR_1_API get24-2Name Battery_TimeControl_2&lt;br /&gt;
attr WR_1_API get24-3Name Battery_TimeControl_3&lt;br /&gt;
attr WR_1_API get24-4Name Battery_TimeControl_4&lt;br /&gt;
attr WR_1_API get24-5Name Battery_TimeControl_5&lt;br /&gt;
attr WR_1_API get24-6Name Battery_TimeControl_6&lt;br /&gt;
attr WR_1_API get24-7Name Battery_TimeControl_7&lt;br /&gt;
attr WR_1_API get24-8Name Battery_TimeControl&lt;br /&gt;
attr WR_1_API get24Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get24Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get24JSON .._value&lt;br /&gt;
attr WR_1_API get24Name 24_Battery_TimeControl&lt;br /&gt;
attr WR_1_API get24URL http://%IP-WR%/api/v1/settings/devices:local/Battery:TimeControl:Enable,Battery:TimeControl:ConfMon,Battery:TimeControl:ConfTue,Battery:TimeControl:ConfWed,Battery:TimeControl:ConfThu,Battery:TimeControl:ConfFri,Battery:TimeControl:ConfSat,Battery:TimeControl:ConfSun&lt;br /&gt;
attr WR_1_API get25Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get25Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API get25Name 25_Battery_EM_State&lt;br /&gt;
attr WR_1_API get25URL http://%IP-WR%/api/v1/processdata/devices:local/EM_State&lt;br /&gt;
attr WR_1_API get40-1Name EnergyMgmt_AcStorage&lt;br /&gt;
attr WR_1_API get40-2Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get40JSON .._value&lt;br /&gt;
attr WR_1_API get40Name 40_Generator_und_EnergieMgmt&lt;br /&gt;
attr WR_1_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable,EnergyMgmt:AcStorage&lt;br /&gt;
attr WR_1_API get41-1Name DigitalOutputs_ConfigurationFlags&lt;br /&gt;
attr WR_1_API get41-2Name DigitalOutputs_DelayTime&lt;br /&gt;
attr WR_1_API get41-3Name DigitalOutputs_PowerMode_OffPowerThreshold&lt;br /&gt;
attr WR_1_API get41-4Name DigitalOutputs_PowerMode_OnPowerThreshold&lt;br /&gt;
attr WR_1_API get41-5Name DigitalOutputs_SwitchOffDuration&lt;br /&gt;
attr WR_1_API get41-6Name DigitalOutputs_TimeMode_MaxNoOfSwitchingCyclesPerDay&lt;br /&gt;
attr WR_1_API get41-7Name DigitalOutputs_TimeMode_PowerThreshold&lt;br /&gt;
attr WR_1_API get41-8Name DigitalOutputs_TimeMode_RunTime&lt;br /&gt;
attr WR_1_API get41-9Name DigitalOutputs_TimeMode_StableTime&lt;br /&gt;
attr WR_1_API get41Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get41Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get41JSON .._value&lt;br /&gt;
attr WR_1_API get41Name 41_DigitalOutputs&lt;br /&gt;
attr WR_1_API get41URL http://%IP-WR%/api/v1/settings/devices:local/DigitalOutputs:Customer:ConfigurationFlags,DigitalOutputs:Customer:DelayTime,DigitalOutputs:Customer:PowerMode:OffPowerThreshold,DigitalOutputs:Customer:PowerMode:OnPowerThreshold,DigitalOutputs:Customer:SwitchOffDuration,DigitalOutputs:Customer:TimeMode:MaxNoOfSwitchingCyclesPerDay,DigitalOutputs:Customer:TimeMode:PowerThreshold,DigitalOutputs:Customer:TimeMode:RunTime,DigitalOutputs:Customer:TimeMode:StableTime&lt;br /&gt;
attr WR_1_API get51Name 51_modules_list&lt;br /&gt;
attr WR_1_API get51URL http://%IP-WR%/api/v1/modules&lt;br /&gt;
attr WR_1_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_1_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_1_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_1_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API get60Name 60_update_status&lt;br /&gt;
attr WR_1_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_API icon sani_solar&lt;br /&gt;
attr WR_1_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_1_API reading0101JSON nonce&lt;br /&gt;
attr WR_1_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_1_API reading0102JSON rounds&lt;br /&gt;
attr WR_1_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_1_API reading0103JSON salt&lt;br /&gt;
attr WR_1_API reading0103Name auth_salt&lt;br /&gt;
attr WR_1_API reading0104JSON transactionId&lt;br /&gt;
attr WR_1_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_1_API reading0201JSON signature&lt;br /&gt;
attr WR_1_API reading0201Name auth_signature&lt;br /&gt;
attr WR_1_API reading0202JSON token&lt;br /&gt;
attr WR_1_API reading0202Name auth_token&lt;br /&gt;
attr WR_1_API reading0301JSON message&lt;br /&gt;
attr WR_1_API reading0301Name info_message&lt;br /&gt;
attr WR_1_API reading0302JSON error&lt;br /&gt;
attr WR_1_API reading0302Name info_error&lt;br /&gt;
attr WR_1_API reading03JSON sessionId&lt;br /&gt;
attr WR_1_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_1_API reading25Name Battery_EM_State&lt;br /&gt;
attr WR_1_API reading25OMap 0:Normal,8:Ruhe1,16:Ruhe2,32:Ausgleichsladung,64:Tiefentladeschutz&lt;br /&gt;
attr WR_1_API reading25Regex EM_State.*value&amp;quot;:(\d+)&lt;br /&gt;
attr WR_1_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_1_API replacement01Mode expression&lt;br /&gt;
attr WR_1_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_1_API replacement01Value {ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_1_API replacement02Mode expression&lt;br /&gt;
attr WR_1_API replacement02Regex %START%&lt;br /&gt;
attr WR_1_API replacement02Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_1_API replacement04Mode expression&lt;br /&gt;
attr WR_1_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_1_API replacement04Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_1_API replacement05Mode expression&lt;br /&gt;
attr WR_1_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_1_API replacement05Value {my $NAME=&amp;quot;WR_1_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_1_API replacement06Mode reading&lt;br /&gt;
attr WR_1_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_1_API replacement06Value auth_signature&lt;br /&gt;
attr WR_1_API replacement07Mode reading&lt;br /&gt;
attr WR_1_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_1_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_1_API replacement08Mode expression&lt;br /&gt;
attr WR_1_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_1_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_1_API replacement09Mode expression&lt;br /&gt;
attr WR_1_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_1_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_1_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set06Method POST&lt;br /&gt;
attr WR_1_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_1_API set06NoArg 1&lt;br /&gt;
attr WR_1_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_1_API set2201Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:DynamicSoc:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2201FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2201Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2201Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2201Hint 0,1&lt;br /&gt;
attr WR_1_API set2201Method PUT&lt;br /&gt;
attr WR_1_API set2201Name 22_01_Battery_DynamicSoc_Enable&lt;br /&gt;
attr WR_1_API set2201URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2203Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinHomeComsumption&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2203FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2203Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2203Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2203Hint slider,50,50,8000&lt;br /&gt;
attr WR_1_API set2203Method PUT&lt;br /&gt;
attr WR_1_API set2203Name 22_03_Battery_MinHomeConsumption&lt;br /&gt;
attr WR_1_API set2203URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2204Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinSoc&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2204FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2204Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2204Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2204Hint slider,5,5,100&lt;br /&gt;
attr WR_1_API set2204Method PUT&lt;br /&gt;
attr WR_1_API set2204Name 22_04_Battery_MinSoc&lt;br /&gt;
attr WR_1_API set2204URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2205Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:SmartBatteryControl:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2205FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2205Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2205Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2205Hint 0,1&lt;br /&gt;
attr WR_1_API set2205Method PUT&lt;br /&gt;
attr WR_1_API set2205Name 22_05_Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr WR_1_API set2205URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2206Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Strategy&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2206FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2206Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2206Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2206Hint 1,2&lt;br /&gt;
attr WR_1_API set2206Method PUT&lt;br /&gt;
attr WR_1_API set2206Name 22_06_Battery_Strategy&lt;br /&gt;
attr WR_1_API set2206URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2207Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Type&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2207FollowGet 22_Battery_InternControl&lt;br /&gt;
attr WR_1_API set2207Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2207Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2207Hint 0,4&lt;br /&gt;
attr WR_1_API set2207Method PUT&lt;br /&gt;
attr WR_1_API set2207Name 22_07_Battery_Type&lt;br /&gt;
attr WR_1_API set2207URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2300Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2300FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2300Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2300Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2300Hint 0,1,2&lt;br /&gt;
attr WR_1_API set2300Method PUT&lt;br /&gt;
attr WR_1_API set2300Name 23_00_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2300URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2301Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:AcPowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2301FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2301Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2301Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2301Method PUT&lt;br /&gt;
attr WR_1_API set2301Name 23_01_Battery_ExternControl_AcPowerAbs&lt;br /&gt;
attr WR_1_API set2301URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2302Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:AcPowerRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2302FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2302Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2302Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2302Method PUT&lt;br /&gt;
attr WR_1_API set2302Name 23_02_Battery_ExternControl_AcPowerRel&lt;br /&gt;
attr WR_1_API set2302URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2303Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcCurrentAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2303FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2303Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2303Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2303Method PUT&lt;br /&gt;
attr WR_1_API set2303Name 23_03_Battery_ExternControl_DcCurrentAbs&lt;br /&gt;
attr WR_1_API set2303URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2304Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcCurrentRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2304FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2304Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2304Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2304Method PUT&lt;br /&gt;
attr WR_1_API set2304Name 23_04_Battery_ExternControl_DcCurrentRel&lt;br /&gt;
attr WR_1_API set2304URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2305Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcPowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2305FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2305Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2305Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2305Method PUT&lt;br /&gt;
attr WR_1_API set2305Name 23_05_Battery_ExternControl_DcPowerAbs&lt;br /&gt;
attr WR_1_API set2305URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2306Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:DcPowerRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2306FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2306Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2306Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2306Method PUT&lt;br /&gt;
attr WR_1_API set2306Name 23_06_Battery_ExternControl_DcPowerRel&lt;br /&gt;
attr WR_1_API set2306URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2307Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxChargePowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2307FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2307Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2307Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2307Method PUT&lt;br /&gt;
attr WR_1_API set2307Name 23_07_Battery_ExternControl_MaxChargePowerAbs&lt;br /&gt;
attr WR_1_API set2307URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2308Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxDischargePowerAbs&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2308FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2308Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2308Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2308Method PUT&lt;br /&gt;
attr WR_1_API set2308Name 23_08_Battery_ExternControl_MaxDischargePowerAbs&lt;br /&gt;
attr WR_1_API set2308URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2309Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MaxSocRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2309FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2309Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2309Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2309Hint slider,30,5,100&lt;br /&gt;
attr WR_1_API set2309Method PUT&lt;br /&gt;
attr WR_1_API set2309Name 23_09_Battery_ExternControl_MaxSocRel&lt;br /&gt;
attr WR_1_API set2309URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2310Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ExternControl:MinSocRel&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2310FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2310Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2310Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2310Hint slider,0,5,100&lt;br /&gt;
attr WR_1_API set2310Method PUT&lt;br /&gt;
attr WR_1_API set2310Name 23_10_Battery_ExternControl_MinSocRel&lt;br /&gt;
attr WR_1_API set2310URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2311Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ComMonitor:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2311FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2311Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2311Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2311Hint 0,1&lt;br /&gt;
attr WR_1_API set2311Method PUT&lt;br /&gt;
attr WR_1_API set2311Name 23_11_Battery_ComMonitor_Enable&lt;br /&gt;
attr WR_1_API set2311URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set2312Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:ComMonitor:Time&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set2312FollowGet 23_Battery_ExternControl&lt;br /&gt;
attr WR_1_API set2312Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set2312Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set2312Hint slider,0,10,600&lt;br /&gt;
attr WR_1_API set2312Method PUT&lt;br /&gt;
attr WR_1_API set2312Name 23_12_Battery_ComMonitor_Time&lt;br /&gt;
attr WR_1_API set2312URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set4002FollowGet 40_Generator_und EnergieMgmt&lt;br /&gt;
attr WR_1_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_1_API set4002Method PUT&lt;br /&gt;
attr WR_1_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_1_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set4101Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:DelayTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;5&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:PowerMode:OnPowerThreshold&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;100000&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:MaxNoOfSwitchingCyclesPerDay&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:PowerThreshold&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:RunTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;30&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;DigitalOutputs:Customer:TimeMode:StableTime&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;}]}]&lt;br /&gt;
attr WR_1_API set4101FollowGet 41_DigitalOutputs&lt;br /&gt;
attr WR_1_API set4101Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set4101Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set4101Hint 0,9,13,14&lt;br /&gt;
attr WR_1_API set4101Method PUT&lt;br /&gt;
attr WR_1_API set4101Name 41_01_DigitalOutputs&lt;br /&gt;
attr WR_1_API set4101URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_1_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_1_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_1_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_1_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_1_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_1_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_1_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_1_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_1_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_1_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_1_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_1_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_1_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_1_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_1_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_1_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_1_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_1_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_1_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_1_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_1_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_1_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_1_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_1_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_1_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_1_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_1_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_1_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_1_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_1_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_1_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_1_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_1_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_1_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_1_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_1_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_1_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_1_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_1_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_1_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_1_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_1_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_1_API set50JSON .&lt;br /&gt;
attr WR_1_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_1_API set50ParseResponse 1&lt;br /&gt;
attr WR_1_API set50TextArg 1&lt;br /&gt;
attr WR_1_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_1_API set6001Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_1_API set6001Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_1_API set6001Method POST&lt;br /&gt;
attr WR_1_API set6001Name 60_01_Reset_Wechselrichter&lt;br /&gt;
attr WR_1_API set6001NoArg 1&lt;br /&gt;
attr WR_1_API set6001URL http://%IP-WR%/api/v1/system/reboot&lt;br /&gt;
attr WR_1_API showBody 1&lt;br /&gt;
attr WR_1_API showError 1&lt;br /&gt;
attr WR_1_API sid01Data %START%&lt;br /&gt;
attr WR_1_API sid01ParseResponse 1&lt;br /&gt;
attr WR_1_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_1_API sid02Data %FINISH%&lt;br /&gt;
attr WR_1_API sid02ParseResponse 1&lt;br /&gt;
attr WR_1_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_1_API sid03Data %SESSION%&lt;br /&gt;
attr WR_1_API sid03ParseResponse 1&lt;br /&gt;
attr WR_1_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_1_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_1_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_1_API sortby 112&lt;br /&gt;
attr WR_1_API stateFormat {\&lt;br /&gt;
 my $calcVal = 0;;\&lt;br /&gt;
 my $WR      = &amp;quot;WR_1&amp;quot;;;\&lt;br /&gt;
 my $YearBefore      = &amp;quot;LogDBRep_Statistic_previous_Year&amp;quot;;;\&lt;br /&gt;
 my $YearPrevious    = ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,&amp;quot;null&amp;quot;);;\&lt;br /&gt;
   $YearPrevious = ($YearPrevious ne &amp;quot;null&amp;quot;) ? POSIX::strftime(&amp;quot;%Y&amp;quot;,localtime(time_str2num(ReadingsTimestamp(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,&amp;quot;null&amp;quot;)))) : &amp;quot;null&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $QuarterBefore   = &amp;quot;LogDBRep_Statistic_previous_Quarter&amp;quot;;;\&lt;br /&gt;
 my $QuarterPrevious = &amp;quot;null&amp;quot;;;\&lt;br /&gt;
 foreach my $i (1,2,3,4) {if (ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,&amp;quot;Q&amp;quot;.$i,0) eq &amp;quot;previous&amp;quot;){ $QuarterPrevious = &amp;quot;Q&amp;quot;.$i }};;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvt   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Total_AC_Active_P&amp;quot;,0) );;\&lt;br /&gt;
 my $pvtd  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvtm  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvtm .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_Yield&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvty  = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvty .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv    = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0) );;\&lt;br /&gt;
 my $pvd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomePv&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvy   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $gfi   =  sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0),0)):  0) );;\&lt;br /&gt;
 my $gfid  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $gfim  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $gfim .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomeFeedInGrid&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $gfiy  = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $gfiy .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $eb    = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal($WR,&amp;quot;Total_Active_P_EM&amp;quot;,0),0) : 0) );;\&lt;br /&gt;
 my $ebd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $ebm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $ebm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_EnergyHomeGrid&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $eby   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $eby  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvb   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0));;\&lt;br /&gt;
 my $pvbd  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $pvbm  = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvbm .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, 158+ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_Statistic_EnergyHomeBat&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $pvby  = sprintf(&amp;quot;%05d&amp;quot;,158+ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $pvby .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $et    = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)+ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0)) );;\&lt;br /&gt;
 my $etd   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Day&amp;quot;,0)/1000 );;\&lt;br /&gt;
 my $etm   = sprintf(&amp;quot;%04d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Month&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $etm  .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %04d&amp;quot;, ReadingsVal(&amp;quot;$QuarterBefore&amp;quot;,$QuarterPrevious.&amp;quot;_SW_Statistic_TotalConsumption&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $ety   = sprintf(&amp;quot;%05d&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Year&amp;quot;,0)/1000 );;\&lt;br /&gt;
    $ety  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %05d&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_TotalConsumption_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $valA  = ReadingsVal($WR, &amp;quot;SW_Total_AC_Active_P&amp;quot;,0)-ReadingsVal($WR, &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,0);;\&lt;br /&gt;
    $calcVal = ($valA &amp;gt; 0) ? round($valA /($valA + ReadingsVal($WR, &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0;;\&lt;br /&gt;
 my $aq    = sprintf(&amp;quot;%4d %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
 \&lt;br /&gt;
 my $aqd   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Day&amp;quot;,0) );;\&lt;br /&gt;
 my $aqm   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Month&amp;quot;,0) );;\&lt;br /&gt;
 my $aqy   = sprintf(&amp;quot;%3d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0) );;\&lt;br /&gt;
    $aqy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %3d %%&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $valS  = ReadingsVal($WR,&amp;quot;SW_Total_AC_Active_P&amp;quot;,0);;\&lt;br /&gt;
    $calcVal = ($valS &amp;gt; 0) ? round((ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,0) + ReadingsVal($WR,&amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,0)) / $valS * 100 ,0) : 0;;\&lt;br /&gt;
 my $sq    =  sprintf(&amp;quot;%4d %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
\&lt;br /&gt;
 my $sqd   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Day&amp;quot;,0) );;\&lt;br /&gt;
 my $sqm   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Month&amp;quot;,0) );;\&lt;br /&gt;
 my $sqy   = sprintf(&amp;quot;%4d %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Year&amp;quot;,0) );;\&lt;br /&gt;
    $sqy  .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? sprintf(&amp;quot; / %3d %%&amp;quot;, ReadingsVal(&amp;quot;$YearBefore&amp;quot;,&amp;quot;SW_Statistic_OwnConsumptionRate_Year&amp;quot;,0) ) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
		   \&lt;br /&gt;
 my $date  = POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;auth_me_authenticated&amp;quot;,0))));;\&lt;br /&gt;
 my $md    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;auth_me_authenticated&amp;quot;,0))));;\&lt;br /&gt;
 my $cd    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Day&amp;quot;,0))));;\&lt;br /&gt;
 my $cm    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Month&amp;quot;,0))));;\&lt;br /&gt;
    $cm   .= ($QuarterPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.POSIX::strftime(&amp;quot;%d.%m&amp;quot;,localtime(time_str2num(ReadingsTimestamp(&amp;quot;$QuarterBefore&amp;quot;,&amp;quot;$QuarterPrevious&amp;quot;,0) ))) : &amp;quot;&amp;quot;;;\&lt;br /&gt;
 my $cy    = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(time_str2num(ReadingsTimestamp($name, &amp;quot;SW_Statistic_Autarky_Year&amp;quot;,0))));;\&lt;br /&gt;
    $cy   .= ($YearPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.$YearPrevious : &amp;quot;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 52%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 12%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Statistik vom $date in kWh&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;aktuell&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Monat&amp;quot;.(($QuarterPrevious ne &amp;quot;null&amp;quot;) ? &amp;quot; / &amp;quot;.$QuarterPrevious : &amp;quot;&amp;quot;).&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold;;text-align:center&#039;&amp;gt;Jahr&amp;quot;.(($YearPrevious ne &amp;quot;0&amp;quot;) ? &amp;quot; / Vorjahr&amp;quot; : &amp;quot;&amp;quot;).&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Erzeugung PV-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug von PV&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug von Batterie&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvbd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvbm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$pvby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug ins Haus (Energieverbrauch)&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Bezug vom Netz&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Einspeisung ins Netz&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnet um&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:center&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}\&lt;br /&gt;
&lt;br /&gt;
attr WR_1_API timeout 7&lt;br /&gt;
attr WR_1_API userReadings Statistic_EnergyHomePvSum_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;0&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;0&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;0&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;0&amp;quot;) ),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)),0)},\&lt;br /&gt;
Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)),0)},\&lt;br /&gt;
Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyPv1_Day:Statistic_EnergyPv1_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Month:Statistic_EnergyPv1_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Total:Statistic_EnergyPv1_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv1_Year:Statistic_EnergyPv1_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv1_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Day:Statistic_EnergyPv2_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Month:Statistic_EnergyPv2_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Total:Statistic_EnergyPv2_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv2_Year:Statistic_EnergyPv2_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv2_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Day:Statistic_EnergyPv3_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Month:Statistic_EnergyPv3_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Total:Statistic_EnergyPv3_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv3_Year:Statistic_EnergyPv3_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyPv3_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyPv4_Day:Statistic_EnergyPv1_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Month:Statistic_EnergyPv1_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Total:Statistic_EnergyPv1_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv4_Year:Statistic_EnergyPv1_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv1_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Day:Statistic_EnergyPv2_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Month:Statistic_EnergyPv2_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Total:Statistic_EnergyPv2_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv5_Year:Statistic_EnergyPv2_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv2_Year&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Day:Statistic_EnergyPv3_Day.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Month:Statistic_EnergyPv3_Month.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Total:Statistic_EnergyPv3_Total.* monotonic {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyPv6_Year:Statistic_EnergyPv3_Year.* {round(ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_EnergyPv3_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Yield_Day:Statistic_Yield_Day.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Month:Statistic_Yield_Month.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Total:Statistic_Yield_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Total&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_Yield_Year:Statistic_Yield_Year.* {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0)+ReadingsVal(&amp;quot;WR_2_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)),0)},\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0)),0)},\&lt;br /&gt;
SW_Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0)),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Day:SW_Statistic_Yield_Day.* {   (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Day&amp;quot;  ,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Month:SW_Statistic_Yield_Month.* { (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Month&amp;quot;,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeFeedInGrid_Year:SW_Statistic_Yield_Year.* {  (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy-&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_FeedInGrid_Year&amp;quot; ,0)) * 1000 },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Day:SW_Statistic_Yield_Day.* {   (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Day&amp;quot;  ,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Month:SW_Statistic_Yield_Month.* { (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Month&amp;quot;,0)) * 1000 },\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Year:SW_Statistic_Yield_Year.* {  (ReadingsVal(&amp;quot;WR_0_KSEM&amp;quot;,&amp;quot;Active_energy+&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Meter_init_Grid_Year&amp;quot; ,0)) * 1000 },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {  round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;  ,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot; ,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {   round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0),0) },\&lt;br /&gt;
SW_Statistic_EnergyHomePvSum_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0),0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyHome_Day:SW_Statistic_EnergyHomeFeedInGrid_Day.* {ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;  ,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;  ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Day&amp;quot;  ,0) },\&lt;br /&gt;
SW_Statistic_EnergyHome_Month:SW_Statistic_EnergyHomeFeedInGrid_Month.* { ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Month&amp;quot;,0) },\&lt;br /&gt;
SW_Statistic_EnergyHome_Year:SW_Statistic_EnergyHomeFeedInGrid_Year.* { ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot; ,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot; ,0) - ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeFeedInGrid_Year&amp;quot; ,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_TotalConsumption_Day:SW_Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Day&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Day&amp;quot;,0) ) ,0)},\&lt;br /&gt;
SW_Statistic_TotalConsumption_Month:SW_Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Month&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Month&amp;quot;,0) ),0)},\&lt;br /&gt;
SW_Statistic_TotalConsumption_Year:SW_Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Year&amp;quot;,0)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,0) + ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomeGrid_Year&amp;quot;,0) ),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Autarky_Day:SW_Statistic_EnergyHomePvSum_Day.* { my $SW_Statistic_EnergyHome_Day = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Day&amp;quot;,0) ;; ($SW_Statistic_EnergyHome_Day eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Day&amp;quot;,0) / $SW_Statistic_EnergyHome_Day *100,0) },\&lt;br /&gt;
SW_Statistic_Autarky_Month:SW_Statistic_EnergyHomePvSum_Month.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Month&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Month&amp;quot;,0) *100,0) },\&lt;br /&gt;
SW_Statistic_Autarky_Year:SW_Statistic_EnergyHomePvSum_Year.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Year&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Year&amp;quot;,0) *100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Day:SW_Statistic_EnergyHomePvSum_Day.* {my $SW_Statistic_Yield_Day = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Day&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Day eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Day&amp;quot;  ,0) / $SW_Statistic_Yield_Day*100,0) },\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Month:SW_Statistic_EnergyHomePvSum_Month.* {my $SW_Statistic_Yield_Month = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Month&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Month eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Month&amp;quot;  ,0) / $SW_Statistic_Yield_Month*100,0) },\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Year:SW_Statistic_EnergyHomePvSum_Year.* {my $SW_Statistic_Yield_Year = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Year&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Year eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePvSum_Year&amp;quot;  ,0) / $SW_Statistic_Yield_Year*100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_EnergyChargeGrid_Total:Statistic_EnergyChargeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyChargeInvIn_Total:Statistic_EnergyChargeInvIn_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargeInvIn_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyChargePv_Total:Statistic_EnergyChargePv_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyChargePv_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyDischargeGrid_Total:Statistic_EnergyDischargeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyDischargeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyDischarge_Total:Statistic_EnergyDischarge_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyDischarge_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeBat_Total:Statistic_EnergyHomeBat_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeGrid_Total:Statistic_EnergyHomeGrid_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomeOwn_Total:Statistic_EnergyHomeOwn_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeOwn_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHomePv_Total:Statistic_EnergyHomePv_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Total&amp;quot;,0),0)},\&lt;br /&gt;
SW_Statistic_EnergyHome_Total:Statistic_EnergyHome_Total.* monotonic {round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHome_Total&amp;quot;,0),0)},\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_Autarky_Total:SW_Statistic_EnergyHomePv_Total.* { round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Total&amp;quot;,0) / ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHome_Total&amp;quot;,0) *100,0) },\&lt;br /&gt;
\&lt;br /&gt;
SW_Statistic_OwnConsumptionRate_Total:SW_Statistic_EnergyHomePv_Total.* {my $SW_Statistic_Yield_Total = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_Yield_Total&amp;quot;,0) ;;;; ($SW_Statistic_Yield_Total eq 0)? 0 : round(ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;SW_Statistic_EnergyHomePv_Total&amp;quot; ,0) / $SW_Statistic_Yield_Total*100,0) }&lt;br /&gt;
attr WR_1_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Initiales setzen der WR_0_KSEM Zähler Stände. Dies sollte nach einem save config durch das setstate, bei einem restart wieder richtig gesetzt sein. Das ganze neu berechnen der Statistiken ist nur ein Work around, bis Kostal das Problem in der Firmware korrigiert hat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_FeedInGrid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Day   xxxx   &amp;lt;&amp;lt; Tageswert  um 00:01&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Month xxxx   &amp;lt;&amp;lt; Monatswert um 00:01 am 01. des Monats&lt;br /&gt;
setstate WR_1_API SW_Meter_init_Grid_Year  xxxx   &amp;lt;&amp;lt; Jahreswert um 00:01 am 01.01 des Jahres&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erweiterung im PV_Schedule, um die Zählerstände zu speichern&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 1)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Man kann den Schaltausgangdes Wechselrichtern mit &amp;quot;set 41_01_DigitalOutputs&amp;quot; auch direkt schalten.&lt;br /&gt;
&lt;br /&gt;
Dies ist jedoch keine original Funktion des Wechselrichters, sondert manipuliert die Konfiguration des Schaltausgangs.&lt;br /&gt;
&lt;br /&gt;
Testaufbau: Ne lange Leitung bis ins warme Büro und ein Durchgangsprüfer am Potentialfreien Relais Ausgang des Plenticore.&lt;br /&gt;
&lt;br /&gt;
Nebenergebnis: Der Summer am 40 Jahre alten Messgerät ist kaputt und die Gewährleistung ist rum.&lt;br /&gt;
&lt;br /&gt;
Es soll festgestellt werden, ob man das Relais mit den oben vorgegebenen Angaben Ein- und Ausschalten kann.&lt;br /&gt;
&lt;br /&gt;
Ergebnis: Es funktioniert und konnte sogar noch vereinfacht werden, wenn man das &amp;quot;DigitalOutputs:Customer:ConfigurationFlags &#039;&#039;&#039;0&#039;&#039;&#039;&amp;quot; verwendet. Alle anderen Parameter dienen lediglich der Basis Konfiguration und wurden im Test einfach per default mitgesendet. Nur &amp;quot;DigitalOutputs:Customer:ConfigurationFlags&amp;quot; wechselt, um das Ein- und Ausschalten zu erreichen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausschalten&#039;&#039;&#039; wird mit der Sendefolge 9-0 erreicht und schaltet direkt nach der 9 ab. Die oben genannte Abschaltverzögerung wird anscheinend vom Flag 9 sofort zurückgesetzt. Das Senden von Flag 0 dektiviert die Digital Ausgang konfiguration und verhindert das erneute Einschalten durch die vorherige Sendung von Flag 9.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einschalten&#039;&#039;&#039; erfolgt grundsätzlich mit einer minimum Verzögerung von 1 Minute. Der Startzustand ist Flag 0 und die Einschaltung erfolgt einfach mit Flag 9 (nach 1 Minute).&lt;br /&gt;
&lt;br /&gt;
Umgesetzt habe ich das ganze in FHEM mit dem HTTPMOD Modul. Hier gibt es nun einen SET Aufruf, der das Flag inklusieve aller Konfigurations Parameter (siehe oben das json) übermittelt. Anschließend wird ein GET für diesen Aufruf gemacht, der den Status im FHEM aktualisiert.&lt;br /&gt;
&lt;br /&gt;
Die sleep 1 sind hierbei nicht erforderlich, da die Kommunikation selber bereits syncronisiert ist und es sich beim Test gezeigt hat, das diese Verzögerung durch das GET ausreicht.&lt;br /&gt;
&lt;br /&gt;
Generell ist natürlich nochmals zu erwähnen, dass es leider nicht möglich ist den Relais Status abzufragen. Die einzige Prüfung, die eventuell noch etwas mehr Sicherheit geben könnte wäre eine Nachverfolgung des Flags in einer Art Schrittschaltung. Hierbei könnte man wie oben erwähnt nach dem Senden des Flags eine direkte Abfrage anhängen und anschließend das nächste Flag senden und wieder abfragen.&lt;br /&gt;
&lt;br /&gt;
Beispiel der Schaltreihenfolge:&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
9   =&amp;gt; Ein nach 1 Minute&lt;br /&gt;
&lt;br /&gt;
9-0 =&amp;gt; Aus, das Flag bleibt nun auf 0&lt;br /&gt;
&lt;br /&gt;
Durch die 9 schaltet es bereits ab, würde jedoch nach 1 Minute wieder an gehen.&lt;br /&gt;
&lt;br /&gt;
Die 0 deaktiviert die Steuerung komplett.&lt;br /&gt;
&lt;br /&gt;
Ich denke durch diese Vorgehensweise kann man auch die anderen Schaltkonfigurationen im Wechsel verwenden. Die Abschaltung sollte dann jeweils durch die Wiederholung der aktuell aktiven Konfiguration gefolgt vom Flag 0 erfolgen.&lt;br /&gt;
&lt;br /&gt;
Anschließend kann dann die neu gewüschte Konfiguration folgen.&lt;br /&gt;
&lt;br /&gt;
Somit wäre das Flag 0 dann auch das Signal für ein auf jeden Fall abgeschaltetes Relais.&lt;br /&gt;
&lt;br /&gt;
======RAW Definition des WR_2_API Slave ab v1.16======&lt;br /&gt;
Auch hier kann man im Schwarm für den zweiten Wechselrichter eine verkürzte definition verwenden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_2_API HTTPMOD http://%IP-WR%/api/v1/auth/me 0&lt;br /&gt;
attr WR_2_API DbLogExclude .*&lt;br /&gt;
attr WR_2_API DbLogInclude Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API authRetries 1&lt;br /&gt;
attr WR_2_API comment Version 2021.04.27 16:00\&lt;br /&gt;
Passworte für die Abfrage des WR_2_API werden im storeKeyValue abgelegt:\&lt;br /&gt;
   {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;Device Name&amp;gt;_&amp;lt;Benutzer Name&amp;gt;&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}\&lt;br /&gt;
   {KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_WR_2_API_user&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
attr WR_2_API disable 0&lt;br /&gt;
attr WR_2_API dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_2_API enableControlSet 0&lt;br /&gt;
attr WR_2_API enableCookies 1&lt;br /&gt;
attr WR_2_API event-on-update-reading auth_.*,Statistic_EnergyPv[1|2|3].*,Statistic_Yield.*&lt;br /&gt;
attr WR_2_API get01Data %START%&lt;br /&gt;
attr WR_2_API get01Name 01_auth_start&lt;br /&gt;
attr WR_2_API get01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API get02Data %FINISH%&lt;br /&gt;
attr WR_2_API get02Name 02_auth_finish&lt;br /&gt;
attr WR_2_API get02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API get03Data %SESSION%&lt;br /&gt;
attr WR_2_API get03Name 03_auth_create_session&lt;br /&gt;
attr WR_2_API get03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API get04-1Name auth_me_active&lt;br /&gt;
attr WR_2_API get04-2Name auth_me_locked&lt;br /&gt;
attr WR_2_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr WR_2_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr WR_2_API get04-5Name auth_me_role&lt;br /&gt;
attr WR_2_API get04-6Name auth_me_permissions&lt;br /&gt;
attr WR_2_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get04JSON .&lt;br /&gt;
attr WR_2_API get04Name 04_auth_me&lt;br /&gt;
attr WR_2_API get04URL http://%IP-WR%/api/v1/auth/me&lt;br /&gt;
attr WR_2_API get05-1Name info_api_version&lt;br /&gt;
attr WR_2_API get05-2Name info_hostname&lt;br /&gt;
attr WR_2_API get05-3Name info_name&lt;br /&gt;
attr WR_2_API get05-4Name info_sw_version&lt;br /&gt;
attr WR_2_API get05JSON .&lt;br /&gt;
attr WR_2_API get05Name 05_info_version&lt;br /&gt;
attr WR_2_API get05URL http://%IP-WR%/api/v1/info/version&lt;br /&gt;
attr WR_2_API get20-10Format %.2f&lt;br /&gt;
attr WR_2_API get20-10Name Statistic_EnergyChargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-11Format %.2f&lt;br /&gt;
attr WR_2_API get20-11Name Statistic_EnergyChargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-12Format %.2f&lt;br /&gt;
attr WR_2_API get20-12Name Statistic_EnergyChargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-13Format %.2f&lt;br /&gt;
attr WR_2_API get20-13Name Statistic_EnergyChargeInvIn_Day&lt;br /&gt;
attr WR_2_API get20-14Format %.2f&lt;br /&gt;
attr WR_2_API get20-14Name Statistic_EnergyChargeInvIn_Month&lt;br /&gt;
attr WR_2_API get20-15Format %.2f&lt;br /&gt;
attr WR_2_API get20-15Name Statistic_EnergyChargeInvIn_Total&lt;br /&gt;
attr WR_2_API get20-16Format %.2f&lt;br /&gt;
attr WR_2_API get20-16Name Statistic_EnergyChargeInvIn_Year&lt;br /&gt;
attr WR_2_API get20-17Format %.2f&lt;br /&gt;
attr WR_2_API get20-17Name Statistic_EnergyChargePv_Day&lt;br /&gt;
attr WR_2_API get20-18Format %.2f&lt;br /&gt;
attr WR_2_API get20-18Name Statistic_EnergyChargePv_Month&lt;br /&gt;
attr WR_2_API get20-19Format %.2f&lt;br /&gt;
attr WR_2_API get20-19Name Statistic_EnergyChargePv_Total&lt;br /&gt;
attr WR_2_API get20-1Format %.2f&lt;br /&gt;
attr WR_2_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr WR_2_API get20-20Format %.2f&lt;br /&gt;
attr WR_2_API get20-20Name Statistic_EnergyChargePv_Year&lt;br /&gt;
attr WR_2_API get20-21Format %.2f&lt;br /&gt;
attr WR_2_API get20-21Name Statistic_EnergyDischarge_Day&lt;br /&gt;
attr WR_2_API get20-22Format %.2f&lt;br /&gt;
attr WR_2_API get20-22Name Statistic_EnergyDischarge_Month&lt;br /&gt;
attr WR_2_API get20-23Format %.2f&lt;br /&gt;
attr WR_2_API get20-23Name Statistic_EnergyDischarge_Total&lt;br /&gt;
attr WR_2_API get20-24Format %.2f&lt;br /&gt;
attr WR_2_API get20-24Name Statistic_EnergyDischarge_Year&lt;br /&gt;
attr WR_2_API get20-25Format %.2f&lt;br /&gt;
attr WR_2_API get20-25Name Statistic_EnergyDischargeGrid_Day&lt;br /&gt;
attr WR_2_API get20-26Format %.2f&lt;br /&gt;
attr WR_2_API get20-26Name Statistic_EnergyDischargeGrid_Month&lt;br /&gt;
attr WR_2_API get20-27Format %.2f&lt;br /&gt;
attr WR_2_API get20-27Name Statistic_EnergyDischargeGrid_Total&lt;br /&gt;
attr WR_2_API get20-28Format %.2f&lt;br /&gt;
attr WR_2_API get20-28Name Statistic_EnergyDischargeGrid_Year&lt;br /&gt;
attr WR_2_API get20-29Format %.2f&lt;br /&gt;
attr WR_2_API get20-29Name Statistic_EnergyHome_Day&lt;br /&gt;
attr WR_2_API get20-2Format %.2f&lt;br /&gt;
attr WR_2_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr WR_2_API get20-30Format %.2f&lt;br /&gt;
attr WR_2_API get20-30Name Statistic_EnergyHome_Month&lt;br /&gt;
attr WR_2_API get20-31Format %.2f&lt;br /&gt;
attr WR_2_API get20-31Name Statistic_EnergyHome_Total&lt;br /&gt;
attr WR_2_API get20-32Format %.2f&lt;br /&gt;
attr WR_2_API get20-32Name Statistic_EnergyHome_Year&lt;br /&gt;
attr WR_2_API get20-33Format %.2f&lt;br /&gt;
attr WR_2_API get20-33Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr WR_2_API get20-34Format %.2f&lt;br /&gt;
attr WR_2_API get20-34Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr WR_2_API get20-35Format %.2f&lt;br /&gt;
attr WR_2_API get20-35Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr WR_2_API get20-36Format %.2f&lt;br /&gt;
attr WR_2_API get20-36Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr WR_2_API get20-37Format %.2f&lt;br /&gt;
attr WR_2_API get20-37Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr WR_2_API get20-38Format %.2f&lt;br /&gt;
attr WR_2_API get20-38Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr WR_2_API get20-39Format %.2f&lt;br /&gt;
attr WR_2_API get20-39Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr WR_2_API get20-3Format %.2f&lt;br /&gt;
attr WR_2_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr WR_2_API get20-40Format %.2f&lt;br /&gt;
attr WR_2_API get20-40Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr WR_2_API get20-41Format %.2f&lt;br /&gt;
attr WR_2_API get20-41Name Statistic_EnergyHomeOwn_Total&lt;br /&gt;
attr WR_2_API get20-42Format %.2f&lt;br /&gt;
attr WR_2_API get20-42Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr WR_2_API get20-43Format %.2f&lt;br /&gt;
attr WR_2_API get20-43Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr WR_2_API get20-44Format %.2f&lt;br /&gt;
attr WR_2_API get20-44Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr WR_2_API get20-45Format %.2f&lt;br /&gt;
attr WR_2_API get20-45Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr WR_2_API get20-46Format %.2f&lt;br /&gt;
attr WR_2_API get20-46Name Statistic_EnergyPv1_Day&lt;br /&gt;
attr WR_2_API get20-47Format %.2f&lt;br /&gt;
attr WR_2_API get20-47Name Statistic_EnergyPv1_Month&lt;br /&gt;
attr WR_2_API get20-48Format %.2f&lt;br /&gt;
attr WR_2_API get20-48Name Statistic_EnergyPv1_Total&lt;br /&gt;
attr WR_2_API get20-49Format %.2f&lt;br /&gt;
attr WR_2_API get20-49Name Statistic_EnergyPv1_Year&lt;br /&gt;
attr WR_2_API get20-4Format %.2f&lt;br /&gt;
attr WR_2_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr WR_2_API get20-50Format %.2f&lt;br /&gt;
attr WR_2_API get20-50Name Statistic_EnergyPv2_Day&lt;br /&gt;
attr WR_2_API get20-51Format %.2f&lt;br /&gt;
attr WR_2_API get20-51Name Statistic_EnergyPv2_Month&lt;br /&gt;
attr WR_2_API get20-52Format %.2f&lt;br /&gt;
attr WR_2_API get20-52Name Statistic_EnergyPv2_Total&lt;br /&gt;
attr WR_2_API get20-53Format %.2f&lt;br /&gt;
attr WR_2_API get20-53Name Statistic_EnergyPv2_Year&lt;br /&gt;
attr WR_2_API get20-54Format %.2f&lt;br /&gt;
attr WR_2_API get20-54Name Statistic_EnergyPv3_Day&lt;br /&gt;
attr WR_2_API get20-55Format %.2f&lt;br /&gt;
attr WR_2_API get20-55Name Statistic_EnergyPv3_Month&lt;br /&gt;
attr WR_2_API get20-56Format %.2f&lt;br /&gt;
attr WR_2_API get20-56Name Statistic_EnergyPv3_Total&lt;br /&gt;
attr WR_2_API get20-57Format %.2f&lt;br /&gt;
attr WR_2_API get20-57Name Statistic_EnergyPv3_Year&lt;br /&gt;
attr WR_2_API get20-58Format %.2f&lt;br /&gt;
attr WR_2_API get20-58Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr WR_2_API get20-59Format %.2f&lt;br /&gt;
attr WR_2_API get20-59Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr WR_2_API get20-5Format %.2f&lt;br /&gt;
attr WR_2_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr WR_2_API get20-60Format %.2f&lt;br /&gt;
attr WR_2_API get20-60Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr WR_2_API get20-61Format %.2f&lt;br /&gt;
attr WR_2_API get20-61Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr WR_2_API get20-62Format %.2f&lt;br /&gt;
attr WR_2_API get20-62Name Statistic_Yield_Day&lt;br /&gt;
attr WR_2_API get20-63Format %.2f&lt;br /&gt;
attr WR_2_API get20-63Name Statistic_Yield_Month&lt;br /&gt;
attr WR_2_API get20-64Format %.2f&lt;br /&gt;
attr WR_2_API get20-64Name Statistic_Yield_Total&lt;br /&gt;
attr WR_2_API get20-65Format %.2f&lt;br /&gt;
attr WR_2_API get20-65Name Statistic_Yield_Year&lt;br /&gt;
attr WR_2_API get20-6Format %.2f&lt;br /&gt;
attr WR_2_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr WR_2_API get20-7Format %.2f&lt;br /&gt;
attr WR_2_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr WR_2_API get20-8Format %.2f&lt;br /&gt;
attr WR_2_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr WR_2_API get20-9Format %.2f&lt;br /&gt;
attr WR_2_API get20-9Name Statistic_EnergyChargeGrid_Day&lt;br /&gt;
attr WR_2_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr WR_2_API get20Name 20_Statistic_EnergyFlow&lt;br /&gt;
attr WR_2_API get20URL http://%IP-WR%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr WR_2_API get40Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get40Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get40Name 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API get40URL http://%IP-WR%/api/v1/settings/devices:local/Generator:ShadowMgmt:Enable&lt;br /&gt;
attr WR_2_API get59Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr WR_2_API get59Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get59Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API get59Name 59_logdata_download&lt;br /&gt;
attr WR_2_API get59URL http://%IP-WR%/api/v1/logdata/download&lt;br /&gt;
attr WR_2_API get60Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API get60Name 60_update_status&lt;br /&gt;
attr WR_2_API get60URL http://%IP-WR%/api/v1/update/status&lt;br /&gt;
attr WR_2_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API group PV Eigenverbrauch&lt;br /&gt;
attr WR_2_API icon sani_solar&lt;br /&gt;
attr WR_2_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials|Not authorized&lt;br /&gt;
attr WR_2_API reading0101JSON nonce&lt;br /&gt;
attr WR_2_API reading0101Name auth_nonce&lt;br /&gt;
attr WR_2_API reading0102JSON rounds&lt;br /&gt;
attr WR_2_API reading0102Name auth_rounds&lt;br /&gt;
attr WR_2_API reading0103JSON salt&lt;br /&gt;
attr WR_2_API reading0103Name auth_salt&lt;br /&gt;
attr WR_2_API reading0104JSON transactionId&lt;br /&gt;
attr WR_2_API reading0104Name auth_transactionId&lt;br /&gt;
attr WR_2_API reading0201JSON signature&lt;br /&gt;
attr WR_2_API reading0201Name auth_signature&lt;br /&gt;
attr WR_2_API reading0202JSON token&lt;br /&gt;
attr WR_2_API reading0202Name auth_token&lt;br /&gt;
attr WR_2_API reading0301JSON message&lt;br /&gt;
attr WR_2_API reading0301Name info_message&lt;br /&gt;
attr WR_2_API reading0302JSON error&lt;br /&gt;
attr WR_2_API reading0302Name info_error&lt;br /&gt;
attr WR_2_API reading03JSON sessionId&lt;br /&gt;
attr WR_2_API reading03Name auth_sessionId&lt;br /&gt;
attr WR_2_API reading40Name Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API reading40Regex Generator:ShadowMgmt.*value&amp;quot;:&amp;quot;(\d+)&lt;br /&gt;
attr WR_2_API replacement01Mode expression&lt;br /&gt;
attr WR_2_API replacement01Regex %IP-WR%&lt;br /&gt;
attr WR_2_API replacement01Value {ReadingsVal(&amp;quot;WR_2_config&amp;quot;,&amp;quot;IP-WR_2&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement02Mode expression&lt;br /&gt;
attr WR_2_API replacement02Regex %START%&lt;br /&gt;
attr WR_2_API replacement02Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;start&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;)}&lt;br /&gt;
attr WR_2_API replacement04Mode expression&lt;br /&gt;
attr WR_2_API replacement04Regex %FINISH%&lt;br /&gt;
attr WR_2_API replacement04Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;finish&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement05Mode expression&lt;br /&gt;
attr WR_2_API replacement05Regex %SESSION%&lt;br /&gt;
attr WR_2_API replacement05Value {my $NAME=&amp;quot;WR_2_API&amp;quot;;; plenticore_auth(&amp;quot;session&amp;quot;,&amp;quot;user&amp;quot;,&amp;quot;$NAME&amp;quot;,ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_transactionId&amp;quot;,&amp;quot;missed&amp;quot;),ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;missed&amp;quot;))}&lt;br /&gt;
attr WR_2_API replacement06Mode reading&lt;br /&gt;
attr WR_2_API replacement06Regex %auth_signature%&lt;br /&gt;
attr WR_2_API replacement06Value auth_signature&lt;br /&gt;
attr WR_2_API replacement07Mode reading&lt;br /&gt;
attr WR_2_API replacement07Regex %auth_sessionId%&lt;br /&gt;
attr WR_2_API replacement07Value auth_sessionId&lt;br /&gt;
attr WR_2_API replacement08Mode expression&lt;br /&gt;
attr WR_2_API replacement08Regex %begin_date%&lt;br /&gt;
attr WR_2_API replacement08Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API replacement09Mode expression&lt;br /&gt;
attr WR_2_API replacement09Regex %end_date%&lt;br /&gt;
attr WR_2_API replacement09Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr WR_2_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_2_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set06Method POST&lt;br /&gt;
attr WR_2_API set06Name 06_auth_logout&lt;br /&gt;
attr WR_2_API set06NoArg 1&lt;br /&gt;
attr WR_2_API set06URL http://%IP-WR%/api/v1/auth/logout&lt;br /&gt;
attr WR_2_API set4002Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Generator:ShadowMgmt:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr WR_2_API set4002FollowGet 40_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set4002Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set4002Hint slider,0,1,3&lt;br /&gt;
attr WR_2_API set4002Method PUT&lt;br /&gt;
attr WR_2_API set4002Name 40_02_Generator_ShadowMgmt&lt;br /&gt;
attr WR_2_API set4002URL http://%IP-WR%/api/v1/settings&lt;br /&gt;
attr WR_2_API set50-10Name Event_02_code&lt;br /&gt;
attr WR_2_API set50-11Name Event_02_description&lt;br /&gt;
attr WR_2_API set50-12Name Event_02_end_time&lt;br /&gt;
attr WR_2_API set50-13Name Event_02_group&lt;br /&gt;
attr WR_2_API set50-14Name Event_02_is_active&lt;br /&gt;
attr WR_2_API set50-15Name Event_02_long_description&lt;br /&gt;
attr WR_2_API set50-16Name Event_02_start_time&lt;br /&gt;
attr WR_2_API set50-17Name Event_03_category&lt;br /&gt;
attr WR_2_API set50-18Name Event_03_code&lt;br /&gt;
attr WR_2_API set50-19Name Event_03_description&lt;br /&gt;
attr WR_2_API set50-1Name Event_01_category&lt;br /&gt;
attr WR_2_API set50-20Name Event_03_end_time&lt;br /&gt;
attr WR_2_API set50-21Name Event_03_group&lt;br /&gt;
attr WR_2_API set50-22Name Event_03_is_active&lt;br /&gt;
attr WR_2_API set50-23Name Event_03_long_description&lt;br /&gt;
attr WR_2_API set50-24Name Event_03_start_time&lt;br /&gt;
attr WR_2_API set50-25Name Event_04_category&lt;br /&gt;
attr WR_2_API set50-26Name Event_04_code&lt;br /&gt;
attr WR_2_API set50-27Name Event_04_description&lt;br /&gt;
attr WR_2_API set50-28Name Event_04_end_time&lt;br /&gt;
attr WR_2_API set50-29Name Event_04_group&lt;br /&gt;
attr WR_2_API set50-2Name Event_01_code&lt;br /&gt;
attr WR_2_API set50-30Name Event_04_is_active&lt;br /&gt;
attr WR_2_API set50-31Name Event_04_long_description&lt;br /&gt;
attr WR_2_API set50-32Name Event_04_start_time&lt;br /&gt;
attr WR_2_API set50-33Name Event_05_category&lt;br /&gt;
attr WR_2_API set50-34Name Event_05_code&lt;br /&gt;
attr WR_2_API set50-35Name Event_05_description&lt;br /&gt;
attr WR_2_API set50-36Name Event_05_end_time&lt;br /&gt;
attr WR_2_API set50-37Name Event_05_group&lt;br /&gt;
attr WR_2_API set50-38Name Event_05_is_active&lt;br /&gt;
attr WR_2_API set50-39Name Event_05_long_description&lt;br /&gt;
attr WR_2_API set50-3Name Event_01_description&lt;br /&gt;
attr WR_2_API set50-40Name Event_05_start_time&lt;br /&gt;
attr WR_2_API set50-4Name Event_01_end_time&lt;br /&gt;
attr WR_2_API set50-5Name Event_01_group&lt;br /&gt;
attr WR_2_API set50-6Name Event_01_is_active&lt;br /&gt;
attr WR_2_API set50-7Name Event_01_long_description&lt;br /&gt;
attr WR_2_API set50-8Name Event_01_start_time&lt;br /&gt;
attr WR_2_API set50-9Name Event_02_category&lt;br /&gt;
attr WR_2_API set50Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr WR_2_API set50Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr WR_2_API set50Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr WR_2_API set50Hint en-gb,de-de&lt;br /&gt;
attr WR_2_API set50JSON .&lt;br /&gt;
attr WR_2_API set50Name 50_events_latest_5&lt;br /&gt;
attr WR_2_API set50ParseResponse 1&lt;br /&gt;
attr WR_2_API set50TextArg 1&lt;br /&gt;
attr WR_2_API set50URL http://%IP-WR%/api/v1/events/latest&lt;br /&gt;
attr WR_2_API showBody 1&lt;br /&gt;
attr WR_2_API showError 1&lt;br /&gt;
attr WR_2_API sid01Data %START%&lt;br /&gt;
attr WR_2_API sid01ParseResponse 1&lt;br /&gt;
attr WR_2_API sid01URL http://%IP-WR%/api/v1/auth/start&lt;br /&gt;
attr WR_2_API sid02Data %FINISH%&lt;br /&gt;
attr WR_2_API sid02ParseResponse 1&lt;br /&gt;
attr WR_2_API sid02URL http://%IP-WR%/api/v1/auth/finish&lt;br /&gt;
attr WR_2_API sid03Data %SESSION%&lt;br /&gt;
attr WR_2_API sid03ParseResponse 1&lt;br /&gt;
attr WR_2_API sid03URL http://%IP-WR%/api/v1/auth/create_session&lt;br /&gt;
attr WR_2_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr WR_2_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr WR_2_API sortby 212&lt;br /&gt;
attr WR_2_API timeout 7&lt;br /&gt;
attr WR_2_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Batteriesteuerung über den Plenticore===&lt;br /&gt;
Beim Plenticore ist der Speicher an einem der Stringanschlüsse angeschlossen und die Steuerung obliegt direkt dem Wechselrichter. Aus diesem Grund ist eine Beeinflussung des Speicherverhaltens auch nur über den Wechselrichter möglich. Hierzu gibt es ab der Plenticore Version v1.16 zwei mögliche Schnittstellen. Die bisherige API Schnittstelle und auch die ModBus Schnittstelle, die nun auch das Setzen von Registern ermöglicht.&lt;br /&gt;
In der bisherigen Implementierung in FHEM wird die API Schnittstelle verwendet, da hierüber auch einzelne Funktionalitäten für den Betreiber möglich sind, die auch ohne die Freischaltung der Externen Speichersteuerung möglich sind. Tiefergehende Steuerungen bedürfen der Freischaltung durch den Installateur.&lt;br /&gt;
&lt;br /&gt;
Die bisherige Steuerung des Speichers war im PV_Schedule Device implementiert, was sich jedoch als recht unübersichtlich erwiesen hat. Aktuell wurde ein weiteres DOIF Device eingerichtet, das nun die umfangreichere Bedienung der externen Speichersteuerung übernommen hat. Die Konfiguration wurde ebenfalls wieder in einem DUMMY abgebildet.&lt;br /&gt;
&lt;br /&gt;
====Batteriesteuerung Möglichkeiten====&lt;br /&gt;
=====Speicher Basissteuerung=====&lt;br /&gt;
Einige Speichersteuerungen werden als Grundlegend angesehen und sind deshalb immer aktiv. Diese Funktionalität ist auch ohne die externe Speichersteuerung für den Betreiber möglich.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- smart_laden (bei geringer Leistung im Herbst/Winter)&lt;br /&gt;
- MinSOC Sommer/Winter Umschaltung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
======smart_laden und laden_beendet======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die Steuerung von MinSOC und MinHomeConsumtion ist über das device WR_1_API auch für den Anlagenbetreiber möglich.&lt;br /&gt;
Bei einem schlechten Forecast, z.B. im Herbst/Winter, wurde ein Vorschlag aus dem Photovoltaikform umgesetzt.&lt;br /&gt;
Die Batterie wurde bisher am Tag immer kurz geladen, dann wieder durch z.B. eine Wärmepumpe geleert und das immer im Wechsel.&lt;br /&gt;
Da im Winter ja eh Strom zugekauft werden muss wird nun die Batterie einfach stetig mit dem Überschuss, der nicht sofort verbrauchen kann, geladen.&lt;br /&gt;
Dieser Vorgang wurde als smart_laden und laden_beendet implementiert. Nun ist Ruhe eingekehrt :-),&lt;br /&gt;
&lt;br /&gt;
Laut dem EFT Service ist es zwar kein Problem die Batterie einfach immer wieder kurz zu laden und sofort wieder zu entladen, doch die jetzige Variante sieht etwas schonender aus.&lt;br /&gt;
Das könnte sich dann in längerer Lebenszeit bemerkbar machen, was man aber erst in 10 Jahren behaupten könnte :-)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Umsetzung:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bei MinSOC 15% wird MinHomeConsumtion auf den Wert Battery_Info_WorkCapacity gesetzt und die Batterie kann schön den ganzen Tag laden, oder im Forum vorgeschlagen bis SOC 90% .&lt;br /&gt;
Dadurch, dass MinHomeConsumtion auf die Maximalleistung gesetzt wurde würde die Batterie erst bei diesem Wert entladen dürfen, was eher unwahrscheinlich ist. Wichtig ist nur, dass der gesetzte Wert höher ist, als der zu erwartende Maximalverbrauch des Hauses. Setzt man MinHomeConsumtion auf einen Wert, der den Verbrauch eines Großverbrauchers im Haus nahe kommt, dann würde nur dieser unterstützt. Das nur als Randbemerkung.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Nebeneffekte:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Das Laden der Batterie kann somit auch mal Tage dauern, wenn zu wenig PV Leistung vom Dach kommt.&lt;br /&gt;
- Es wird vermutet, dass der MinSoC Wert bei geringer Leistung in der Batterie ungenau wird,&lt;br /&gt;
   aber bei Ladung bis 100% exakter berechnet wird. MinSoC ist keine exakte Wissenschaft.&lt;br /&gt;
- Stellt der Kontroller der Batterie fest, das die Leistung in der Batterie einen Grenzwert unterschritten hat,&lt;br /&gt;
   wird der MinSoC korrigiert und es kommt zu dem Effekt, das mitten in der Nacht der MinSoC auf einmal&lt;br /&gt;
   nach unten fällt. Damit wird dem Wechselrichter signalisiert, das nachgeladen werden muss, um MinSoC&lt;br /&gt;
   wieder zu erreichen. Das Resultat ist die bekannte Notladung in der Nacht aus dem Netz.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MinSOC Sommer/Winter Umschaltung======&lt;br /&gt;
Dies gehört zur Basissteuerung und schaltet den MinSOC von Sommer auf Winterbetrieb, um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: Ist immer aktiv&lt;br /&gt;
Aktivität  : Im Speicher wird MinSOC verändert&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Die MinSOC Werte wurden vom Hersteller empfohlen&lt;br /&gt;
SpeicherMinSOC_Sommer  5&lt;br /&gt;
SpeicherMinSOC_Winter 20&lt;br /&gt;
&lt;br /&gt;
Der nächste Schwellwert sollte so gewählt werden, ab welcher Forecast Leistung der Speicher noch genügend nachgeladen wird, sodass es keine Notladung in der Nacht gibt. Es ist normal, dass der Speicher hierbei nicht den Bedarf der Nacht decken kann (Herbst/Winter). Das Nachladen sollte jedoch für die Deckung des Eigenverbrauchs vom Plenticore reichen.&lt;br /&gt;
&lt;br /&gt;
SpeicherMinSOC_fc1_Limit 13000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Zeit Steuerung eines Lade-/Entladefensters (Tarifsteuerung)=====&lt;br /&gt;
Für diejenigen, die einen Zeittarif ihres EVU haben, ermöglicht dies ein Zeitfenster zu definieren, in dem der Speicher z.B. bei einem hohen Tarif entladen werden darf. Außerhalb dieser Zeit wird dann das Entladen gesperrt, damit der günstige Tarif genutzt werden kann.&lt;br /&gt;
&#039;&#039;&#039;Achtung, in der Schweiz ist es verboten den Speicher aus dem Netz zu laden&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Verwendung der DOIF Zeitsteuerung ist hier [https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung DOIF_Zeitsteuerung] eine sehr gute Beschreibung zu finden.&lt;br /&gt;
&lt;br /&gt;
======Aktivierung über WR_1_Speicher_1_ExternControl======&lt;br /&gt;
Um die Zeitsteuerung zu verwenden werden im WR_1_Speicher_1_ExternControl Device folgende readings gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger &lt;br /&gt;
  Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API&lt;br /&gt;
  Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst&lt;br /&gt;
  SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung&lt;br /&gt;
&lt;br /&gt;
SpeicherZeitEnde/SpeicherZeitEnde&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.&lt;br /&gt;
&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherEntladung Zeit&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitStart 00:00&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl SpeicherZeitEnde 00:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Um ein flexibles Zeitfenster zu nutzen, ist es möglich die Zeiten z.B. durch ein DOIF oder einen WeekdayTimer dynamisch zu verändern. Hierbei liegt die logische Kontrolle beim Anwender, der für plausible Änderungen zuständig ist.&lt;br /&gt;
&lt;br /&gt;
======PV_1_EVU_Tarif_1 WeekdayTimer (Beispiel)======&lt;br /&gt;
Es gibt hierbei zwei Möglichkeiten, eine Zeitsteuerung umzusetzen, die etwas unterschiedliche Verhaltensweisen ermöglichen.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_1 WeekdayTimer WR_1_Speicher_1_ExternControl  de 12345|00:01|Arbeitstage {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 07:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 16:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_1 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_1 alias PV_1_EVU_Tarif_1&lt;br /&gt;
attr PV_1_EVU_Tarif_1 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_1 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_1 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_1 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_1 sortby 112&lt;br /&gt;
attr PV_1_EVU_Tarif_1 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======PV_1_EVU_Tarif_2 WeekdayTimer (Beispiel)======&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_1_EVU_Tarif_2 WeekdayTimer WR_1_Speicher_1_ExternControl  de  60|00:01|Wochenende {fhem(&amp;quot;setreading $NAME SpeicherZeitStart 00:00&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherZeitEnde 23:59&amp;quot;);; fhem(&amp;quot;setreading $NAME SpeicherEntladung Zeit&amp;quot;)}&lt;br /&gt;
attr PV_1_EVU_Tarif_2 DbLogExclude .*&lt;br /&gt;
attr PV_1_EVU_Tarif_2 alias PV_1_EVU_Tarif_2&lt;br /&gt;
attr PV_1_EVU_Tarif_2 commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr PV_1_EVU_Tarif_2 disable 0&lt;br /&gt;
attr PV_1_EVU_Tarif_2 group PV Steuerung EVU&lt;br /&gt;
attr PV_1_EVU_Tarif_2 icon clock&lt;br /&gt;
attr PV_1_EVU_Tarif_2 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_1_EVU_Tarif_2 sortby 113&lt;br /&gt;
attr PV_1_EVU_Tarif_2 stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======WR_1_Speicher_1_Zeiten WeekdayTimer (Beispiel)======&lt;br /&gt;
In diesem Beispiel wird der frei verwendbare Trigger für die Zeitsteuerung verwendet. Hierbei muss jeder Wechsel zwischen entladen und gesperrt über das reading &amp;quot;SpeicherTrigger [entladen|gesperrt]&amp;quot; gesteuert werden. Ein zurückfallen in ein Zeitfenster ist nicht möglich.&lt;br /&gt;
&#039;&#039;&#039;Nutzung von &amp;quot;SpeicherEntladung Trigger&amp;quot;:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_Zeiten WeekdayTimer SpeicherZeiten de 12345|07:00|entladen 12345|16:00|gesperrt 60|00:00|entladen 60|23:59|gesperrt {fhem(&amp;quot;setreading $NAME SpeicherTrigger $EVENT&amp;quot;)}&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten alias WR_1_Speicher_1_Zeiten&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten commandTemplate set $NAME  $EVENT&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten disable 0&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten group PV Steuerung EVU&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten icon clock&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten sortby 111&lt;br /&gt;
attr WR_1_Speicher_1_Zeiten stateFormat {sprintf(&amp;quot;geplant: %s %s&amp;quot;, ReadingsVal($name,&amp;quot;nextUpdate&amp;quot;,&amp;quot;?&amp;quot;), ReadingsVal($name,&amp;quot;nextValue&amp;quot;,&amp;quot;?&amp;quot;))}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
======Tarifsteuerung mit einem DOIF (Beispiel)======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 1 Setzen des niedrig Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 07:00 - 19:00 Uhr den Speicher zum Entladen&lt;br /&gt;
 ([07:00|8])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 19:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 2 Setzen des hohen Tarifs. Das WR_1_Speicher_1_ExternControl DOIF reagiert dann auf das Zeitfenster und&lt;br /&gt;
##   aktiviert von 00:00 - 23:59 Uhr den Speicher zum Entladen&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 ([00:00|7])&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 00:00)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 23:59)&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)&lt;br /&gt;
&lt;br /&gt;
################################################################################################################&lt;br /&gt;
## 3 Hier könnte dann die Berechnung der überschüssigen Zeit rein, wenn Du mit 40% aus der Nacht kommen würdest&lt;br /&gt;
DOELSEIF&lt;br /&gt;
 (*** )&lt;br /&gt;
&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart [neu berechnete SpeicherZeitStart])&lt;br /&gt;
   (setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit)    ## Triggert den ersten Event, damit die Zeit sofort aktiv wird.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Speicherentladung mit Zeit und Trigger (Beispiel)======&lt;br /&gt;
Dies ist ein spezielles Beispiel, bei dem die Nutzung von &amp;quot;SpeicherEntladung Zeit&amp;quot; mit &amp;quot;SpeicherEntladung SpeicherTrigger&amp;quot; gemeinsam verwendet wird.&lt;br /&gt;
Die Basis ist wie oben beschrieben die Tarifsteuerung mit &amp;quot;SpeicherEntladung Zeit&amp;quot; dies wird durch einen oder mehrere WeekdayTimer mit Zeiten eingestellt. Nach dem setzen einer Zeit wird dies mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung Zeit&amp;quot;)&amp;quot; aktiviert. Soll nun innerhalb des entlade Fensters der Speicher gesperrt werden, so kann man den SpeicherTrigger auf gesperrt setzen und dies dann mit &amp;quot;fhem(&amp;quot;set $NAME SpeicherEntladung SpeicherTrigger&amp;quot;)&amp;quot; aktivieren. Später lässt sich das dann wieder deaktivieren und die Zeitsteuerung läuft wieder weiter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Durch einen Timer wird folgendes täglich um 00:01 Uhr gesetzt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitStart 07:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherZeitEnde 16:00&amp;quot;&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Vor 07:00 Uhr ist der Speicher gesperrt, zwischen 07:00 und 16:00 Uhr geht er auf entladen, danach wieder auf gesperrt.&lt;br /&gt;
&lt;br /&gt;
2.) Mit einem Trigger wird der Speicher in der definierten entlade Zeit für kurze Zeit gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherTrigger gesperrt&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung SpeicherTrigger&lt;br /&gt;
Dadurch wird der Speicher zu einem beliebigen Zeitpunkt auf gesperrt gesetzt, egal wie die Situation der Zeit Steuerung ist.&lt;br /&gt;
&lt;br /&gt;
3.) Rückfall zur vorher eingetragenen Zeit Steuerung&lt;br /&gt;
setreading WR_1_Speicher_1_ExternControl  SpeicherEntladung Zeit&lt;br /&gt;
Der SpeicherTrigger wird abgeschaltet und die zeit Steuerung wieder aktiviert. Es gelten die zuvor eingetragenen Zeiten und der Speicher geht je nach Zeitfenster auf entladen oder gesperrt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig ist hierbei, dass man den gewünschten Zustand zuerst setzt, bevor man die jeweilige Steuerung aktiviert.&#039;&#039;&#039; Ansonsten treten kurze Zustandswechsel auf, die vermieden werden können.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Externe Speichersteuerung (ExternControl)=====&lt;br /&gt;
&#039;&#039;&#039;Für die erweiterte Steuerung muss die externe Speichersteuerung des Plenticore aktiviert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
======Externe Speichersteuerung Ladekontrolle======&lt;br /&gt;
Dies ist eine kurz Beschreibung für einen kompletten Ladezyklusablauf&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Morgens wird geprüft, wie gut der Haushalt durch die Nacht gekommen und wie hoch der MinSOC noch ist&lt;br /&gt;
- Reserve ist 3x MinSOC, also im Sommer 15% und im Winter 60% (im Winter ist der Speicher eh morgens leer :-) )&lt;br /&gt;
- Dann wird ein MaxSOC für den Tag berechnet&lt;br /&gt;
- Bis zum Reserve SOC wir morgens sofort geladen&lt;br /&gt;
​- Danach wird einstellbar mit geringer Leistung am Vormittag bis SOC 30% geladen&lt;br /&gt;
- Innerhalb des Mittagshoch, so meistens dynamisch in der Zeit von 10:00 - 16:00 Uhr&lt;br /&gt;
  wird mit berechneter Leistung bis zum MaxSOC geladen&lt;br /&gt;
​- Man kann auch eine feste Ladeleistung für das Mittagshoch angeben&lt;br /&gt;
​- Am Nachmittag wird der MaxSOC dann weiter gehalten&lt;br /&gt;
- Wird der Speicher am Nachmittag, wegen schlechtem Wetter verwendet, wird der MaxSOC auf 100% angehoben&lt;br /&gt;
- Bei erreichen von SOC 100% wird eine Begrenzung auf MaxSOC 95% durchgeführt, damit nicht ständig nachgeladen wird&lt;br /&gt;
- Spätestens am Abend wird nochmals der MaxSOC von diesem Tag gemerkt, der Zeitpunkt variiert mit der Jahreszeit&lt;br /&gt;
​- Nach ungefähr einer Woche gibt es, wegen des im Speicher berechneten SOC, morgens einen schnellen Abfall&lt;br /&gt;
​  der Entladeleistung. Dadurch fällt der SOC dann so niedrig, dass die Steuerung an diesem Tag auf 100% auflädt,&lt;br /&gt;
​  wodurch der Speicher dann intern den SOC wieder richtig berechnet&lt;br /&gt;
&lt;br /&gt;
Und schon geht das Spiel von vorne los.​&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======MaxSOC Kontrolle======&lt;br /&gt;
Es wird versucht, den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMaxSOCControlActive  An&lt;br /&gt;
Aktivität  : SpeicherMaxSOCControlRunning Aus  = momentan keine Steuerung&lt;br /&gt;
             SpeicherMaxSOC_Actual       100 &amp;lt;&amp;lt;&amp;lt; wird berechnet, kann jedoch für diesen Tag anschließend überschrieben werden&lt;br /&gt;
             SpeicherMaxSOC_DayBefore    100 &amp;lt;&amp;lt;&amp;lt; wird berechnet und dient als Merker&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Dieser Wert muss auf die Anlage angepasst werden und dient als Schwellwert. Die Leistungsangabe soll so hoch sein, dass der Speicher, bei diesem Forecast, auf jeden Fall mit einer Überschussleistung von 3* MinSOC aus der Nacht kommt. Im Frühjahr ist dies besonders gut abzuschätzen, sobald eine Wärmepumpe nachts nicht mehr heizt und nur noch die Grundversorgung in der Nacht aus dem Speicher gedeckt werden muss.&lt;br /&gt;
Durch die Abfrage des Forecasts von morgen ist hierbei berücksichtigt, dass bei einer schlechten Prognose die Speicherladung nicht limitiert wird, was auch im Sommer mal der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
======Middayhigh Kontrolle======&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf. Auch beim Betrieb von zwei Wechselrichtern ist dies wichtig, da mit Stand 03/2021, der Plenticore den Hausverbrauch nicht korrekt ermitteln kann. In diesem Fall funktioniert die &amp;quot;intelligente Batteriesteuerung&amp;quot; nicht mehr und muss deaktiviert werden. Durch die Middayhigh Kontrolle wird aus dem Forecast, durch die Funktion Solar_forecast() eine Überschreitung von Inverer_Max_Power (70%) Regelung ermittelt. Damit kann über die externe Speichersteuerung die Hauptladung des Speichers in die Mittagszeit verlagert werden, um die dynamische 70% Regelung zu nutzen, bevor der Wechselrichter abgeregelt wird.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Aktivierung: SpeicherMiddayControlActive        An&lt;br /&gt;
Aktivität  : SpeicherMiddayControlRunning       Aus = momentan keine Steuerung&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0          0 = Es gibt kein Mittags Hoch. Wird aus Solar_forecast() gesetzt &lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_start 00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
             WR_1:Solar_middayhigh_fc0_stop  00:00  &amp;lt;&amp;lt;&amp;lt;&amp;lt; wird aus dem Forecast berechnet&lt;br /&gt;
&lt;br /&gt;
Konfiguration:&lt;br /&gt;
Der Wert von SpeicherMidday_MaxChargePowerAbs sollte so gewählt werden, dass der Speicher am Vormittag langsam und gleichmäßig bis auf SpeicherMidday_MaxSOC geladen wird.&lt;br /&gt;
Ab der PV_1:Solar_middayhigh_fc0_start wird dann unlimitiert bis zur PV_1:Solar_middayhigh_fc0_stop in der Mittagszeit weiter geladen. Wenn SpeicherMaxSOCControlActive auf 1 ist, wird hierbei weiterhin das Laden limitiert.&lt;br /&gt;
&lt;br /&gt;
SpeicherMidday_Inverter_Max_Power        8500  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hier kann man manuell einen Wert festlegen, wenn es keine 70% Regelung gibt&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_midday  1000  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab; Wird der wert auf 0 gesetzt, so erfolgt eine dynamische Berechnung zur Laufzeit&lt;br /&gt;
SpeicherMidday_MaxChargePowerAbs_morning  450  &amp;lt;&amp;lt;&amp;lt;&amp;lt; hängt vom Speicher ab&lt;br /&gt;
SpeicherMidday_MaxSOC                     30   &amp;lt;&amp;lt;&amp;lt;&amp;lt; Es soll nur bis dahin geladen werden, damit Mittags genug Platz ist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition des WR_1_Speicher_1_ExternControl====&lt;br /&gt;
Achtung, es wurde eine Sperre beim Betrieb einer WallBox eingebaut, die natürlich jeder für sich anpassen, oder gegebenenfalls entfernen muss.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Block 2_smart_Laden_start_WB_1&lt;br /&gt;
- Block 3_smart_Laden_beenden_WB_1&lt;br /&gt;
- Im Block 3_smart_Laden_beenden_Automatik ist eine zusätzliche Bedingung&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
- setstate WR_1_Speicher_1_ExternControl WB_1_smart_laden_before ---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Ladezustand wird hierbei von der WallBox abgefragt und unterscheidet sich bei verschiedenen Herstellern:&lt;br /&gt;
Hier bitte gerne noch weitere WallBoxen bei mir melden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
openWB:&lt;br /&gt;
     [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;&lt;br /&gt;
&lt;br /&gt;
go-eCharger:&lt;br /&gt;
     [WB_1:car_state] eq &amp;quot;2&amp;quot;                           ## Ladevorgang läuft&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das DOIF übernimmt die Externe Speichersteuerung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1_ExternControl DOIF ################################################################################################################\&lt;br /&gt;
## 1 Speicher Status vom WR_1_Speicher_1 aktualisieren.\&lt;br /&gt;
##   Dies geschieht über das WR_1_API Device, da der Speicher direkt am Wechselrichter angeschlossen ist.\&lt;br /&gt;
##\&lt;br /&gt;
1_Status_WR_1_Speicher_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (   [:52]                                                           ## jede Stunde\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Status_Speicher&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 21_Battery_Information&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 22_Battery_InternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 23_Battery_ExternControl&amp;quot;);;\&lt;br /&gt;
    ::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;);;\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_1  : Speicher Status abfrage&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Wenn die Ladung im Herbst/Winter unter MinSoc geht allen PV Überschuss in die Batterie laden\&lt;br /&gt;
##\&lt;br /&gt;
## Im Winter kann der MinSoc, durch den WR Eigenverbrauch, unterschritten werden, deshalb wird vorher auf\&lt;br /&gt;
## smarte_laden umgeschaltet, bis die Batterie wieder einen hohen Soc erreicht hat. Siehe cmd_3 laden_beendet\&lt;br /&gt;
##\&lt;br /&gt;
2_smart_Laden_start_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [WR_ctl:Yield_fc0_day] &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit]     ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
       and [WR_1:Act_state_of_charge] &amp;lt;= [WR_1_API:Battery_InternControl_MinSoc]  ## Achtung der Speicherstand wird zu niedrig\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100             ## Der Speicher steht auf Entladen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_start&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.1: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.1: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
2_smart_Laden_start_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [WB_1:lp_1_ChargeStat]      eq &amp;quot;loading&amp;quot;                        ## Ein Fahrzeug wird gerade geladen\&lt;br /&gt;
     and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;Aus&amp;quot;                            ## Der Speicher darf nicht zum Laden verwendet werden\&lt;br /&gt;
     or\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot;                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_starten_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot; ) {\&lt;br /&gt;
      if([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and\&lt;br /&gt;
         [WR_1_API:Battery_InternControl_MinHomeConsumption] eq &amp;quot;30000&amp;quot; ) {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before aktiv&amp;quot;);;                ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before aktiv&amp;quot;};;\&lt;br /&gt;
      } else {\&lt;br /&gt;
        fhem(&amp;quot;setreading $SELF WB_1_smart_laden_before inaktiv&amp;quot;);;              ## Den vorherigen Zustand merken\&lt;br /&gt;
        if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_2.2: WallBox smart_laden_before inaktiv&amp;quot;};;\&lt;br /&gt;
      }\&lt;br /&gt;
    } else {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;= 0)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_2.2: WallBox es wird gerade geladen&amp;quot;};;       ## Der vorherige Zustand war schon bekannt\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);; ## Speicher für Entladung sperren\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_2.2: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_2.2: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Beim erreichen von 90% Soc die Entladung wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Automatik\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:SpeicherEntladung] eq &amp;quot;Automatik&amp;quot;                            ## Nur für den Automatik Modus\&lt;br /&gt;
     and\&lt;br /&gt;
     [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                            ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100         ## Das Speicher Entladen ist geperrt\&lt;br /&gt;
       and\&lt;br /&gt;
       [WR_1:Act_state_of_charge] &amp;gt;= 80                                  ## Der Speicher ist bereits 80% voll\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot;                   ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell aktiviert\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.1: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.1: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
3_smart_Laden_beenden_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;inaktiv&amp;quot;                      ## Vorher war es nicht aktiv\&lt;br /&gt;
      )\&lt;br /&gt;
     or  [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;                             ## Der Speicher darf zum Laden verwendet werden\&lt;br /&gt;
     or  [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
    )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_WB_1&amp;quot; ) {           ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                       ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.2: Batterie wird mit &amp;quot;.[?$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.2: Batterie auf &amp;quot;.[?WR_1:Act_state_of_charge].&amp;quot; %, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (    [WB_1:lp_1_ChargeStat] eq &amp;quot;loading&amp;quot;\&lt;br /&gt;
        and [$SELF:SpeicherWB_1_buffer] eq &amp;quot;An&amp;quot;) {\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF cmd_3.2: MaxSOC Limitierung wegen Wallboxnutzung abgeschaltet&amp;quot;;;}\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;none&amp;quot;);;                        ## den externen Trigger wieder freigeben\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Wenn vor dem WB_1 laden das smart_Laden aktiv gewesen ist geht es zurück in den Zustand\&lt;br /&gt;
## \&lt;br /&gt;
3_smart_Laden_umschalten_WB_1\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       [WB_1:lp_1_ChargeStat] ne &amp;quot;loading&amp;quot;                               ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
      and\&lt;br /&gt;
       [$SELF:WB_1_smart_laden_before] eq &amp;quot;aktiv&amp;quot;                        ## Vorher war es nicht aktiv\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_umschalten_WB_1&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;WB_1_smart_laden_before&amp;quot;,&amp;quot;---&amp;quot;);;                        ## den Merker wieder zurück setzen\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: WB_1 laden beendet, reaktivieren des smart_Laden&amp;quot;};;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                     ## Externe Trigger verriegeln \&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF cmd_3.3: smart_laden aktiviert&amp;quot;;;\&lt;br /&gt;
        Log 3, &amp;quot;$SELF cmd_3.3: SpeicherExternTrigger, Entlademodus gesperrt&amp;quot;;;\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Bei Zeitsteuerung und guter Prognose bei 40% wieder frei geben\&lt;br /&gt;
##   \&lt;br /&gt;
3_smart_Laden_beenden_Zeit\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and [$SELF:SpeicherEntladung]  eq &amp;quot;Zeit&amp;quot;                            ## Nur für den Zeit Modus\&lt;br /&gt;
     and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]            ## Zeitfenster aktiv ist\&lt;br /&gt;
     and [$SELF:WB_1_smart_laden_before] eq &amp;quot;---&amp;quot;                        ## Es wird gerade kein Fahrzeug geladen\&lt;br /&gt;
     and\&lt;br /&gt;
      (\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (\&lt;br /&gt;
            [WR_1:Act_state_of_charge] &amp;gt;= 40                             ## und einem Stand von Soc 40%\&lt;br /&gt;
        and\&lt;br /&gt;
            ([WR_ctl:Yield_fc0_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit]   ## wenn es heute oder \&lt;br /&gt;
          or [WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit])  ## morgen viel Leistung gibt\&lt;br /&gt;
       )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden_zeit&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;smart_Laden_beenden&amp;quot; ) {                ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                 ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF cmd_3.3: Batterie wird mit &amp;quot;.[$SELF:SpeicherEntladung].&amp;quot; Steuerung gesteuert&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Batterie auf &amp;quot;.[WR_1:Act_state_of_charge].&amp;quot; %, SpeicherExternTrigger, freigegeben&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_3.3: Die Leistungsprognose von &amp;quot;.[$SELF:SpeicherMinSOC_fc1_Limit].&amp;quot; wird überschritten&amp;quot;};;\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherExternTrigger&amp;quot;,&amp;quot;frei&amp;quot;);;                         ## Trigger freigeben\&lt;br /&gt;
    set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                           ## Signalisiere entladen im stateFormat\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);; ## Speicher für Entladung freigeben\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Freigabe der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. ([07:00-16:00]\&lt;br /&gt;
4_Trigger\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;gt; 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitStart]-[$SELF:SpeicherZeitEnde]]       ## Zeitfenster aktiv ist\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot;                               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Trigger&amp;quot; ) {                             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 50&amp;quot;);;  ## Speicher für Entladung freigeben\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;entladen&amp;quot;);;                            ## Signalisiere entladen im stateFormat\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_4  : SpeicherExternTrigger, Entlademodus freigegeben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Sperren der Batterie mit externem Trigger oder bei Zeitsteuerung\&lt;br /&gt;
##   z.B. [16:00-07:00]\&lt;br /&gt;
5_Trigger_sperren\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
      (    [$SELF:SpeicherExternTrigger] eq &amp;quot;frei&amp;quot;                       ## Verriegelung, wenn zwangsgeladen werden muss\&lt;br /&gt;
       and [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt;= 100\&lt;br /&gt;
       and\&lt;br /&gt;
       (      [$SELF:SpeicherEntladung] eq &amp;quot;Trigger&amp;quot;                     ## Triggersteuerung\&lt;br /&gt;
          and [$SELF:SpeicherTrigger]   eq &amp;quot;entladen&amp;quot;                    ## also Speicherentladung freigeben\&lt;br /&gt;
        or                                                                         \&lt;br /&gt;
              [$SELF:SpeicherEntladung] eq &amp;quot;Zeit&amp;quot;                        ## oder bei Zeitsteuerung wenn das\&lt;br /&gt;
          and [[$SELF:SpeicherZeitEnde]-[$SELF:SpeicherZeitStart]]       ## Zeitfenster verlassen wurde\&lt;br /&gt;
       )\&lt;br /&gt;
      )\&lt;br /&gt;
\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Trigger_sperren&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
  ::CommandSet(undef, &amp;quot;WR_1_API 22_03_Battery_MinHomeConsumption 30000&amp;quot;);;## Speicher für Entladung sperren\&lt;br /&gt;
  set_Reading(&amp;quot;SpeicherTrigger&amp;quot;,&amp;quot;gesperrt&amp;quot;);;                             ## Signalisiere gesperrt im stateFormat\&lt;br /&gt;
  if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
    {Log 3, &amp;quot;$SELF cmd_5  : SpeicherExternTrigger, Entlademodus gesperrt (Tarif oder Trigger)&amp;quot;};;\&lt;br /&gt;
 }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
6_Kommando_Wiederholung\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [WR_1_API:Battery_Control] &amp;gt; 0 and                                ## Wenn die ExternControl am WR konfiguriert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatActive]  eq &amp;quot;An&amp;quot; and                      ## Wenn die ExternControl Aktiviert ist\&lt;br /&gt;
       [$SELF:SpeicherCmdRepeatRunning] eq &amp;quot;An&amp;quot; and                      ## Wenn es  ExternControl Kommandos zum Senden gibt\&lt;br /&gt;
       [  {sunrise_abs(&amp;quot;HORIZON=+5.0&amp;quot;,0,&amp;quot;6:00&amp;quot;,&amp;quot;08:35&amp;quot;)}                 ## Innerhalb der Photovoltaik Zeit\&lt;br /&gt;
        - {sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)} ] and\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung&amp;quot; ) {              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   my $MaxChargePowerTime = 0;;\&lt;br /&gt;
   my $MaxChargePowerAbs_midday = 0;;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {                              ## Hier können noch Testmeldungen hin\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : SpeicherMiddayControlRunning &amp;quot;.[$SELF:SpeicherMiddayControlRunning];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_start   &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start];;\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_Test : Yield_fc0_middayhigh_stop    &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop];;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlRunning] eq &amp;quot;An&amp;quot; ) {                  ## Wurde ein Mittagshoch ermittelt und aktiviert?\&lt;br /&gt;
\&lt;br /&gt;
     if ( [WR_1:Act_state_of_charge] &amp;gt;= [WR_1_API:Battery_InternControl_MinSoc] *3 ) {\&lt;br /&gt;
       if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs 0&amp;quot;);;     ## nicht vor z.B. 09:00 Uhr starten. Ladung auf 0 Watt setzen\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                                              ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[$SELF:SpeicherMidday_NotBefore].&amp;quot; Uhr noch nicht laden&amp;quot;;;\&lt;br /&gt;
         }\&lt;br /&gt;
       } else {                                                          ## Ist noch Vormittag?\&lt;br /&gt;
         if ( time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
           ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning]);;\&lt;br /&gt;
           set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMidday_MaxSOC].&#039;)&#039;);;\&lt;br /&gt;
           if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                       ## Es wird nur langsam geladen und MaxSOC limitiert.\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl vor &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; limitieren&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf &amp;quot;.[$SELF:SpeicherMidday_MaxChargePowerAbs_morning].&amp;quot; limitiert&amp;quot;;;\&lt;br /&gt;
             Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSOC auf &amp;quot;.[$SELF:SpeicherMidday_MaxSOC].&amp;quot; % limitiert&amp;quot;;;\&lt;br /&gt;
           }\&lt;br /&gt;
         }\&lt;br /&gt;
       }\&lt;br /&gt;
     } else {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_6  : Battery_InternControl_MinSoc auf &amp;quot;.([WR_1_API:Battery_InternControl_MinSoc] *3).&amp;quot; % laden&amp;quot;;;\&lt;br /&gt;
     }\&lt;br /&gt;
\&lt;br /&gt;
     if (::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) &amp;lt;= time and  ## Es ist Mittag\&lt;br /&gt;
         time &amp;lt;= ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {\&lt;br /&gt;
\&lt;br /&gt;
       my $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;)+3600 ));;\&lt;br /&gt;
          $wait = POSIX::strftime(&amp;quot;%H:%M&amp;quot;,localtime(::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot;:00&amp;quot;) ));;\&lt;br /&gt;
\&lt;br /&gt;
       if ([$SELF:SpeicherMaxSOCControlRunning] eq &amp;quot;An&amp;quot; and                     ## Somit bleibt weniger Platz im Speicher und es ist\&lt;br /&gt;
           time &amp;lt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.$wait.&amp;quot;:00&amp;quot;) ) {  ## besser nicht zu früh beginnen.\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden wegen MaxSoc von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; auf &amp;quot;.$wait.&amp;quot; Uhr verschoben&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
       } else {                                                                 ## auch jetzt nicht mit voller Leistung laden\&lt;br /&gt;
\&lt;br /&gt;
         if ([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0) {            ## dynamische Leistungsermittlung oder vorgewählter Wert\&lt;br /&gt;
           $MaxChargePowerTime       = ::round((::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) - time) / 3600 , 2);;  ## Mittags Ladezeit bestimmen\&lt;br /&gt;
\&lt;br /&gt;
           my $MaxChargePowerLimit   = (1 - ::round($MaxChargePowerTime,2) * [$SELF:SpeicherMidday_MaxChargePowerSteigung]);;  ## Zu Beginn etwas langsamer anfangen, empirisch ermittelt\&lt;br /&gt;
\&lt;br /&gt;
           $MaxChargePowerAbs_midday = ::round( [WR_1:Battery_work_capacity] * ([$SELF:SpeicherMaxSOC_Actual] - [WR_1:Act_state_of_charge]) / 100 * $MaxChargePowerLimit, 0);;\&lt;br /&gt;
\&lt;br /&gt;
           if ($MaxChargePowerAbs_midday &amp;lt; 500) { $MaxChargePowerAbs_midday = 500 };;## Nicht unter 1000\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Mittags $MaxChargePowerTime h mit $MaxChargePowerAbs_midday W laden&amp;quot;;;\&lt;br /&gt;
         } else {\&lt;br /&gt;
           $MaxChargePowerAbs_midday = [$SELF:SpeicherMidday_MaxChargePowerAbs_midday];; ## Nimm den vorgewählten Wert\&lt;br /&gt;
         };;\&lt;br /&gt;
\&lt;br /&gt;
         ::CommandSet(undef, &amp;quot;WR_1_API 23_07_Battery_ExternControl_MaxChargePowerAbs $MaxChargePowerAbs_midday&amp;quot;);;\&lt;br /&gt;
         set_Exec(&amp;quot;wait_ExternControl&amp;quot;,4,&#039;::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.&#039;.[$SELF:SpeicherMaxSOC_Actual].&#039;)&#039;);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControlActive laden von &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_start].&amp;quot; bis &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; freigegeben&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxChargePowerAbs auf $MaxChargePowerAbs_midday limitiert&amp;quot;;;\&lt;br /&gt;
           Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;\&lt;br /&gt;
         };;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
\&lt;br /&gt;
     if (time &amp;gt; ::time_str2num(POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time)).&amp;quot; &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot;:00&amp;quot;) ) {    ## Es ist Nachmittag und die\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                                         ## Mittagssteuerung wird abgeschaltet\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_6  : SpeicherMiddayControl nach &amp;quot;.[WR_ctl:Yield_fc0_middayhigh_stop].&amp;quot; beendet&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;An&amp;quot; and ## Nur MaxSOC soll begrenzt werden\&lt;br /&gt;
       [$SELF:SpeicherMaxSOC_Actual] &amp;lt;= 100                        and                                          \&lt;br /&gt;
       ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;Aus&amp;quot;) { ##  sobald die Mittagssteuerung fertig ist\&lt;br /&gt;
     if ([WR_1:SW_Home_own_consumption_from_Battery] &amp;gt; 500) {             ## Sollte der Speicher bereits jetzt verwendet werden ist es besser\&lt;br /&gt;
       set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                 ## die MaxSOC Begrenzung zu stoppen\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : SpeicherMaxSOCControl wegen Speicher Nutzung am Nachmittag beendet&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
       ::CommandSet(undef, &amp;quot;WR_1_API 23_09_Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual]);;\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_6  : Battery_ExternControl_MaxSocRel &amp;quot;.[$SELF:SpeicherMaxSOC_Actual].&amp;quot; % halten&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_6  : ExternControl Kommando Wiederholung erledigt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Bestimmung eines möglichen SOC für den nächsten Morgen und\&lt;br /&gt;
##   Vorbereitung für ein Leistungshoch am Mittag\&lt;br /&gt;
##\&lt;br /&gt;
7_SOC_Calculation\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
       ([WR_1_API:Battery_Control] &amp;gt; 0 and                               ## Ist die ExternControl am WR aktiviert\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot;   or                ## Ist MaxSOC Limit konfiguriert\&lt;br /&gt;
         [$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; ) and               ## Ist Midday Kontrolle konfiguriert\&lt;br /&gt;
        [$SELF:SpeicherMaxSOC_MinSOC_Time]  eq &amp;quot;NULL&amp;quot; and                ## Wurde ein minimum SOC bereits ermittelt\&lt;br /&gt;
        [{sunrise_abs(&amp;quot;HORIZON=+4.0&amp;quot;,0,&amp;quot;5:50&amp;quot;,&amp;quot;08:35&amp;quot;)} - 10:00 ] and\&lt;br /&gt;
        [WR_1:SW_Home_own_consumption_from_PV] == [WR_1:SW_Home_own_consumption] ## Die PV Leistung reicht für&#039;s Haus\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;SOC_Calculation&amp;quot; ) {                     ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   my $MinSOC_Time   = &amp;quot;gefunden&amp;quot;;;                                       ## Nur einmal am Tag bearbeiten\&lt;br /&gt;
   my $MinSOC_MinSOC = ::round([WR_1:Act_state_of_charge],0);;            ## Festgestellter MinSOC am Morgen          Magic ???\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,$MinSOC_Time);;\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,$MinSOC_MinSOC);;\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {                               ## merken und melden\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_MinSOC_Time &amp;quot;.$MinSOC_Time.&amp;quot; &amp;quot;.$MinSOC_MinSOC.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMaxSOCControlActive] eq &amp;quot;An&amp;quot; and\&lt;br /&gt;
       [WR_1_API:Battery_InternControl_MinHomeConsumption] &amp;lt; 100 and     ## Der Speicher darf nicht im smart_laden sein\&lt;br /&gt;
       [Pool_Counter:countsPerDay] == 0 and                              ## Achtung der Pool und auch die LWP\&lt;br /&gt;
       [LWP_Counter:countsPerDay]  == 0 ) {                              ##    sollten nicht mehr früh morgens laufen\&lt;br /&gt;
\&lt;br /&gt;
     my $SpeicherSOCMinimum = [WR_1_API:Battery_InternControl_MinSoc]*3;; ## 3x MinSOC als reserve vorsehen\&lt;br /&gt;
     my $SpeicherSOCDayBefore = ::round(ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;, 100),0);; ## wie voll war er gestern noch?\&lt;br /&gt;
     my $SpeicherSOCNew       = 0;;\&lt;br /&gt;
     my $SpeicherSOCDelta     = 0;;\&lt;br /&gt;
\&lt;br /&gt;
     if ([WR_ctl:Yield_fc1_day] &amp;gt; [$SELF:SpeicherMaxSOC_fc1_Limit] and\&lt;br /&gt;
         $MinSOC_MinSOC                   &amp;gt; $SpeicherSOCMinimum ) {      ## Ist der Speicher voller als er müsste?\&lt;br /&gt;
\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; %&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Leistung Prognose &amp;quot;.[WR_ctl:Yield_fc1_day].&amp;quot; wh &amp;gt; Schwellwert &amp;quot;.[$SELF:SpeicherMaxSOC_fc1_Limit].&amp;quot; wh&amp;quot;;;\&lt;br /&gt;
         Log 3, &amp;quot;$SELF cmd_7  : Speicherladung aktuell $MinSOC_MinSOC % &amp;gt; Minimum $SpeicherSOCMinimum %&amp;quot;;;\&lt;br /&gt;
       };;\&lt;br /&gt;
       $SpeicherSOCDelta = $MinSOC_MinSOC - $SpeicherSOCMinimum;;         ## Was wäre noch übrig?\&lt;br /&gt;
       if ($SpeicherSOCDelta &amp;lt;= 10) {                                    ## Das lohnt sich nicht\&lt;br /&gt;
         $SpeicherSOCNew = $SpeicherSOCDayBefore;;                        ## den Wert von gestern einfach beibehalten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCDayBefore);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCDayBefore.&amp;quot; % gesichert&amp;quot;};;\&lt;br /&gt;
       } else {\&lt;br /&gt;
         $SpeicherSOCNew = ::round(($SpeicherSOCDayBefore+$SpeicherSOCDayBefore-$SpeicherSOCDelta)/2 ,0);;  ## um den Durchschnitt verringern\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,$SpeicherSOCNew);;           ## Das soll heute in den Speicher\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore &amp;quot;.$SpeicherSOCNew.&amp;quot; % neu berechnet und gesichert&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
       if ($SpeicherSOCNew &amp;gt; 0) {                                        ## Es gibt einen neuen MaxSoc\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;               ## Senden starten\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Wiederholung starten\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual &amp;quot;.$SpeicherSOCNew.&amp;quot; % geplant&amp;quot;};;\&lt;br /&gt;
       } else {                                                          ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt&amp;quot;};;\&lt;br /&gt;
       };;\&lt;br /&gt;
\&lt;br /&gt;
     } else {                                                            ## MaxSoc wird nicht begrenzt\&lt;br /&gt;
       if ($MinSOC_MinSOC  &amp;lt; $SpeicherSOCMinimum ) {                     ## MaxSoc leicht erhöhen, da er etwas zu niedrig war\&lt;br /&gt;
         $SpeicherSOCNew   = ::round($SpeicherSOCDayBefore+$SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         $SpeicherSOCDelta = ::round($SpeicherSOCMinimum-$MinSOC_MinSOC ,0);;\&lt;br /&gt;
         set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,$SpeicherSOCNew);;\&lt;br /&gt;
         if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
           {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_DayBefore wurde um &amp;quot;.$SpeicherSOCDelta.&amp;quot; erhöht&amp;quot;};;\&lt;br /&gt;
       }\&lt;br /&gt;
       if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF cmd_7  : SpeicherMaxSOC_Actual wird nicht begrenzt, da die Prognose für morgen zu schlecht ist&amp;quot;};;\&lt;br /&gt;
     };;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   if ([$SELF:SpeicherMiddayControlActive] eq &amp;quot;An&amp;quot; and                   ## Soll für mittags noch Platz gehalten werden?\&lt;br /&gt;
       [WR_ctl:Yield_fc0_middayhigh] == 1 ) {                                                    \&lt;br /&gt;
																	                           \&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## Die Mittagskontrolle aktivieren\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3){                              ## (die Uhrzeiten wurden bereits durch Solar_forecast() im WR_1 Device eingetragen)\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie SpeicherMiddayControlRunning vorbereitet&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_start &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_start&amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_7  : Batterie Yield_fc0_middayhigh_stop  &amp;quot;.ReadingsVal(&amp;quot;WR_ctl&amp;quot;,&amp;quot;Yield_fc0_middayhigh_stop &amp;quot;, &amp;quot;00:00&amp;quot;).&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {                                                              ## Kein Mittagshoch\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_7  : SpeicherMiddayControl es wird kein Middayhigh geben&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
#############\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Reset der ExternControl Kommandos\&lt;br /&gt;
##\&lt;br /&gt;
8_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,0,&amp;quot;16:00&amp;quot;,&amp;quot;21:00&amp;quot;)}]                ## hier sollte das Ende der PV-Zeit sein\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot;                                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Reset&amp;quot; ) {                               ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
																			                   \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Max SOC Steuerung zurücksetzen\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                           ## SpeicherMaxSOC_Actual auf Default\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_DayBefore&amp;quot;,[WR_1:Act_state_of_charge]);;   ## Den vor Tages Wert merken\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOC_MinSOC_Time&amp;quot;,&amp;quot;NULL&amp;quot;);;                     ## Die MinSOC Time löschen\&lt;br /&gt;
																						       \&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Midday Steuerung zurücksetzen\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc0_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh 0&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_start 00:00&amp;quot;);;\&lt;br /&gt;
   fhem(&amp;quot;setreading WR_ctl Yield_fc1_middayhigh_stop  00:00&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_8  : ExternControl zurückgesetzt&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird, das ist dann im Herbst/Winter\&lt;br /&gt;
##\&lt;br /&gt;
9_MinSOC_Winter\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;lt; [$SELF:SpeicherMinSOC_fc1_Limit] and        ## Wenn morgen das Minimum an Leistung nicht erreicht wird\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;lt; [$SELF:SpeicherMinSOC_Winter]    and        ## und der MinSoc unter der Winter Wert eingestellt ist\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot; or\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;NULL&amp;quot; and [10:01])\&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Winter&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Winter]);;        ## Den MinSOC anheben, um eine eventuelle\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : Batterie MinSoc auf Winterbetrieb&amp;quot;};;        ## Notladung zu verhindern\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                        ## Stop das regelmäßige senden der Kommandos\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## Im Winter Betrieb keine MaxSOC Begrenzung\&lt;br /&gt;
   set_Reading(&amp;quot;SpeicherMiddayControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;                    ## und keine Midday Steuerung\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_9  : MaxSOC Begrenzung und Midday Steuerung im Winterbetrieb deaktiviert&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Umschaltung des MinSoc wenn viel Leistung erwartet wir, das wäre dann Frühling/Sommer\&lt;br /&gt;
##\&lt;br /&gt;
10_MinSOC_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ([WR_ctl:Yield_fc1_day]                  &amp;gt; [$SELF:SpeicherMinSOC_fc1_Limit] and         ## sobald viel Ladung erwartet wird und der MinSoc noch\&lt;br /&gt;
        [WR_1_API:Battery_InternControl_MinSoc] &amp;gt; [$SELF:SpeicherMinSOC_Sommer]    and         ## noch im Winter Modus ist\&lt;br /&gt;
        [10:09] \&lt;br /&gt;
       )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot;                                ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Sommer&amp;quot; ) {                              ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
                                                                                           \&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 22_04_Battery_MinSoc &amp;quot;.[$SELF:SpeicherMinSOC_Sommer]);;        ## den MinSOC auf Sommerbetrieb herabsetzen, es kann\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF cmd_10 : Batterie MinSoc auf Sommerbetrieb&amp;quot;};;                              ## wieder mehr Leistung genutzt werden\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Der Speicher ist voll geladen. Hier wird das ständige nachladen auf 100 % vermieden.\&lt;br /&gt;
##\&lt;br /&gt;
11_Speicher_voll\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
       ( [WR_ctl:Yield_fc0_day]        &amp;gt;  [$SELF:SpeicherMaxSOC_fc1_Limit] and    ## 1) sobald viel Leistung erwartet wird und der Speicher voll ist\&lt;br /&gt;
         [WR_1:Act_state_of_charge]    == 100                              and    ##    den MaxSOC wieder reduzieren, damit nicht immer nachgeladen wird\&lt;br /&gt;
         [$SELF:SpeicherMaxSOC_Actual] ne 95                                      ##   \&lt;br /&gt;
        or\&lt;br /&gt;
        ([$SELF:SpeicherMaxSOC_Actual] == 95 and                                  ## 2) oder das Nachladen gestoppt wurde\&lt;br /&gt;
         [WR_1:Act_state_of_charge] &amp;lt;=  98  and                                   ##    und der SOC unte 98 % gefallen ist\&lt;br /&gt;
         [{sunset_abs(&amp;quot;HORIZON=+8.0&amp;quot;,-7200,&amp;quot;15:00&amp;quot;,&amp;quot;21:00&amp;quot;)}])                    ##    zwei Stunden vor Sonnenuntergang eventuell wieder nachladen\&lt;br /&gt;
       ) and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Speicher_voll&amp;quot; ) {                       ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if ([WR_1:Act_state_of_charge] &amp;lt;= 98) {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;100&amp;quot;);;                         ## Eventuell noch mal nachladen\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 100 % nachladen&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOC_Actual&amp;quot;,&amp;quot;95&amp;quot;);;\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherCmdRepeatRunning&amp;quot;,&amp;quot;An&amp;quot;);;                       ## Start regelmäßiges senden der Kommandos\&lt;br /&gt;
     set_Reading(&amp;quot;SpeicherMaxSOCControlRunning&amp;quot;,&amp;quot;An&amp;quot;);;                   ## MaxSOC Begrenzung weil Speicher bereits 100 % hat\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
       Log 3, &amp;quot;$SELF cmd_11 : Battery_ExternControl_MaxSocRel auf 95 % reduziert&amp;quot;;;\&lt;br /&gt;
     };;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 WR_1_Speicher_1 DC_Power_Abs setzen z.B. zur Zwangsentladung\&lt;br /&gt;
##     dies muss manuell wiederholt werden. Danach hängt es vom WR ab, wie er die Speichersteuerung fortsetzt.\&lt;br /&gt;
12_DC_Power_Abs \&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot;                             ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;DC_Power_Abs&amp;quot; ) {                        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs &amp;quot;.[$SELF:SpeicherDcPowerAbs]);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_12 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 13 WR_1_Speicher_1 Status aktualisieren.\&lt;br /&gt;
##   Dies ist momentan nur für den BYD HV Speicher, da der BYD HVS eine direkte Abfrage nicht unterstützt.\&lt;br /&gt;
##   Wer keinen BYD HV Speicher hat kann das löschen\&lt;br /&gt;
13_Status_WR_1_Speicher_1_BYD\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
      or\&lt;br /&gt;
      [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;Status_WR_1_Speicher_1_BYD&amp;quot; ) {          ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                  ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 BatteryInformation&amp;quot;);;\&lt;br /&gt;
   ::CommandGet(undef, &amp;quot;WR_1_Speicher_1 StatisticInformation&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=4) {\&lt;br /&gt;
      Log 3, &amp;quot;$SELF cmd_13 : Speicher Status abfrage, BYD HV direkt&amp;quot;\&lt;br /&gt;
    }\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 14_Lüfter_ein\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 15_Lüfter_aus\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 17 Wiederhole alle 180s das Kommando für die DcPowerAbs Steuerung\&lt;br /&gt;
##\&lt;br /&gt;
17_Kommando_Wiederholung_DcPowerAbs\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
      ((\&lt;br /&gt;
       [$SELF:SpeicherTriggerLaden] eq &amp;quot;An&amp;quot;  and                         ## Ist der Trigger für das Zwangsladen aktiv?\&lt;br /&gt;
       [$SELF:SpeicherDcPowerAbs]   ne 0     and                         ## Wurde eine Lade/Entlade Leistung eingestellt?\&lt;br /&gt;
       [+([WR_1_API:Battery_ComMonitor_Time]-30)]                        ## Den Befehl nach eingestellter Zeit wiederholen\&lt;br /&gt;
      )\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if( [$SELF:ui_command_1] eq &amp;quot;Kommando_Wiederholung_DcPowerAbs&amp;quot; ) {   ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;WR_1_API 23_05_Battery_ExternControl_DcPowerAbs [$SELF:SpeicherDcPowerAbs]&amp;quot;);;\&lt;br /&gt;
   set_Exec(&amp;quot;17_Battery_EM_State&amp;quot;,30,&#039;::CommandGet(undef, &amp;quot;WR_1_API 25_Battery_EM_State&amp;quot;)&#039;);;\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3) {\&lt;br /&gt;
     Log 3, &amp;quot;$SELF cmd_17 : Battery_ExternControl_DcPowerAbs auf &amp;quot;.[$SELF:SpeicherDcPowerAbs].&amp;quot; gesetzt&amp;quot;;;\&lt;br /&gt;
   };;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl alias WR_1_Speicher_1_ExternControl&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl comment Version 2023.06.21 14:00\&lt;br /&gt;
\&lt;br /&gt;
Hier können externe Trigger für die Ladung und Entladung Der Batterie gesetzt werden.\&lt;br /&gt;
Die Zeiten können z.B. durch den WeekDayTimer entsprechend an einen Stromtarif angepasst werden.\&lt;br /&gt;
Das reading SpeicherEntladung Automatik/Zeit/SpeicherTrigger ermöglicht es die Zeitsteuerung zu überschreiben.\&lt;br /&gt;
\&lt;br /&gt;
ExternTrigger\&lt;br /&gt;
Das reading dient dem Freigeben und Sperren der externen Trigger, z.B. um im Herbst/Winter das smart_laden zu steuern.\&lt;br /&gt;
Es verriegelt somit die Zeitsteuerung oder den SpeicherTrigger.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherEntladung:Automatik,Zeit,SpeicherTrigger \&lt;br /&gt;
Automatik - Der Speicher wird vom Wechselrichter gesteuert, oder über die eigene ExternControl der API\&lt;br /&gt;
Zeit - Das Laden und Entladen wird mit den Zeitwerten beeinflusst\&lt;br /&gt;
SpeicherTrigger - beeinflusst das Laden und Entladen direkt ohne die Zeitsteuerung\&lt;br /&gt;
\&lt;br /&gt;
SpeicherTrigger:entladen,gesperrt\&lt;br /&gt;
Dieser Trigger kann durch ander Logik gesetzt werden.\&lt;br /&gt;
Auch hier wäre eine Zeitsteuerung denkbar, die entladen/gesperrt entsprechend umschaltet.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherZeitStart/SpeicherZeitEnde\&lt;br /&gt;
Die Zeitangaben können manuell fest gesetzt werden, oder über zusätzliche Timer täglich neu überschrieben werden.\&lt;br /&gt;
Eine gültige Zeit und entsprechendes Timeing obliegt dem Anwender.\&lt;br /&gt;
Zwischen Start und Ende wird der Speicher zum Entladen freigegeben und zwischen Ende und Start gesperrt.\&lt;br /&gt;
\&lt;br /&gt;
Speicher*ControlActive\&lt;br /&gt;
Das jeweilige reading aktiviert diese Teilkomponente für die Steuerung.\&lt;br /&gt;
Ein jeweiliges Speicher*ControlRunning signalisiert, ob gerade die Bedingungen erfüllt sind.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherCmdRepeatActive\&lt;br /&gt;
Es muss im WR die externe Speicher Steuerung aktiviert sein.\&lt;br /&gt;
Möchte man trotzdem die Sendung der ExternControl Kommandos stoppen, obwohl die Bedingungen erfüllt sind,\&lt;br /&gt;
kann man dieses reading zum Deaktivieren auf 0 setzen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMiddayControl\&lt;br /&gt;
Über die Solar_forecast() Funktion wird ein Middayhigh ermittelt, wenn der WR nur 70% einspeisen darf.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMaxSOCControl\&lt;br /&gt;
Es wird versucht den Speicher am Abend nicht zu 100% zu laden, aber morgens noch mit 3* MinSOC aus der Nacht zu kommen.\&lt;br /&gt;
\&lt;br /&gt;
SpeicherMinSOC\&lt;br /&gt;
Dies gehört zur Basis Steuerung und schaltet den MinSOC von Sommer auf Winter Betrieb,\&lt;br /&gt;
um eine Notladung aus dem Netz zu vermeiden.&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl disable 0&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl readingList SpeicherExternTrigger SpeicherCmdRepeatActive SpeicherZeitStart SpeicherZeitEnde SpeicherEntladung SpeicherTrigger SpeicherMiddayControlActive SpeicherMidday_Inverter_Max_Power SpeicherMidday_MaxChargePowerAbs_morning SpeicherMidday_MaxChargePowerAbs_midday SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC SpeicherMidday_NotBefore SpeicherMinSOC_Sommer SpeicherMinSOC_Winter SpeicherMinSOC_fc1_Limit SpeicherMaxSOCControlActive SpeicherMaxSOC_Actual SpeicherMaxSOC_DayBefore SpeicherMaxSOC_fc1_Limit&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl setList SpeicherExternTrigger:frei,gesperrt SpeicherCmdRepeatActive:0,1 SpeicherZeitStart:time SpeicherZeitEnde:time SpeicherEntladung:Automatik,Zeit,Trigger SpeicherTrigger:entladen,gesperrt,none SpeicherMiddayControlActive:0,1 SpeicherMidday_Inverter_Max_Power:slider,3000,500,20000 SpeicherMidday_MaxChargePowerAbs_morning:slider,0,50,1000 SpeicherMidday_MaxChargePowerAbs_midday:slider,0,100,4700 SpeicherMidday_MaxChargePowerSteigung SpeicherMidday_MaxSOC:slider,20,5,50 SpeicherMidday_NotBefore:time SpeicherMinSOC_Sommer:slider,5,1,20 SpeicherMinSOC_Winter:slider,5,1,20 SpeicherMinSOC_fc1_Limit:slider,7000,500,17000 SpeicherMaxSOCControlActive:0,1 SpeicherMaxSOC_Actual:slider,60,5,100 SpeicherMaxSOC_DayBefore:slider,15,5,100 SpeicherMaxSOC_fc1_Limit:slider,10000,2000,50000&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl sortby 122&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
##  $TR{0} = &amp;quot;style=&#039;color:yellow;;text-align:left;;font-weight:bold;;font-size:18px&#039;&amp;quot;;;                                                         ## Reihe 0 für Überschrift\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_batt {\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
    my $ret=&amp;quot;position:absolute;;left:&amp;quot;.(90*$val/100).&amp;quot;px;;width:90px;;height:20px;;background:linear-gradient( to right,#F8F8E0 &amp;quot;.(90-(90*$val/100)).&amp;quot;px,rgba(0,0,0,0) &amp;quot;.(90-(90*$val/100)).&amp;quot;px);;&amp;quot;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
#########################################################\&lt;br /&gt;
## &amp;quot;Spalte 0&amp;quot;|&amp;quot;Spalte 1&amp;quot;|&amp;quot;Spalte 2&amp;quot;|&amp;quot;Spalte 3&amp;quot;|&amp;quot;Spalte 4&amp;quot;|&amp;quot;Spalte 5&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / DcPowerAbs / Status&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,Status_Speicher,smart_Laden_start,smart_Laden_beenden,smart_Laden_starten_WB_1,smart_Laden_beenden_WB_1,Kommando_Wiederholung,SOC_Calculation,Reset,DC_Power_Abs,Sommer,Winter,Speicher_voll,14_Luefter_ein,15_Luefter_aus,Status_WR_1_Speicher_1_BYD&amp;quot;) | widget([$SELF:SpeicherDcPowerAbs],&amp;quot;selectnumbers,-4500,250,4500,0,lin&amp;quot;).&amp;quot;W&amp;quot;.widget([$SELF:SpeicherTriggerLaden],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |[WR_1_API:Battery_EM_State]|([$SELF:SpeicherExternTrigger] eq &amp;quot;gesperrt&amp;quot; and [WR_1_API:Battery_InternControl_MinHomeConsumption] == 30000)?&#039;&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;smart_Laden aktiv&amp;lt;/span&amp;gt;&#039;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Speicher&amp;lt;dd&amp;gt;Steuerung&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherEntladung],&amp;quot;uzsuDropDown,Automatik,Trigger,Zeit&amp;quot;) |&amp;quot;WB_1 Laden &amp;quot;.widget([$SELF:SpeicherWB_1_buffer],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|\&lt;br /&gt;
FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,&amp;quot;Laden&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Standby&amp;quot;,15,&amp;quot;red&amp;quot;,&amp;quot;Entladen&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.FUNC_Status([WR_1:Act_state_of_charge],15,&amp;quot;red&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,&amp;quot;orange&amp;quot;,&amp;quot;Speicher SOC&amp;quot;,49,&amp;quot;green&amp;quot;,&amp;quot;Speicher SOC&amp;quot;)|\&lt;br /&gt;
\&lt;br /&gt;
 FUNC_Status([WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],-10,&amp;quot;green&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],&amp;quot;orange&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P],15,&amp;quot;red&amp;quot;,[WR_1:Actual_Battery_charge_-minus_or_discharge_-plus_P]).&amp;quot; W&amp;quot;.&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([WR_1:Act_state_of_charge])).STY(::round([WR_1:Act_state_of_charge],0).&amp;quot;%&amp;quot;,&amp;quot;font-size:16px;;position:absolute;;top:2px;;left:30px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Trigger&amp;lt;dd&amp;gt;Status / ExternTrigger / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherTrigger],&amp;quot;uzsuDropDown,entladen,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherExternTrigger],&amp;quot;uzsuDropDown,frei,gesperrt,none&amp;quot;) | widget([$SELF:SpeicherZeitStart],&amp;quot;time&amp;quot;) | widget([$SELF:SpeicherZeitEnde],&amp;quot;time&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Kommando Wiederholung&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherCmdRepeatActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherCmdRepeatRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMaxSOCControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMaxSOCControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;) |&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MaxSOC Limit&amp;lt;dd&amp;gt;fc1_Limit / Minimum SOC Zeit / gestern / geplant&amp;lt;/dd&amp;gt;&amp;quot; |\&lt;br /&gt;
FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMaxSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;). widget([$SELF:SpeicherMaxSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;) | ([$SELF:SpeicherMaxSOC_MinSOC_Time] eq &amp;quot;gefunden&amp;quot;)?(POSIX::strftime(&amp;quot;%H:%M&amp;quot;,::localtime(::time_str2num(::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;SpeicherMaxSOC_MinSOC_MinSOC&amp;quot;,&amp;quot;&amp;quot;)))).&amp;quot; &amp;quot;.[$SELF:SpeicherMaxSOC_MinSOC_MinSOC].&amp;quot; %&amp;quot;):&amp;quot;wartet&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_DayBefore])).STY(&amp;quot;gestern&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_DayBefore],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; |\&lt;br /&gt;
&amp;quot;&amp;lt;div style=&#039;border-width:2px;;border-style:solid;;border-color:gray;;position:relative;;width:90px;;height:20px;;background:linear-gradient( to right, red 0px,yellow 30px,green 50px);;&#039;&amp;gt;&amp;quot;.STY(&amp;quot; &amp;quot;,FUNC_batt([$SELF:SpeicherMaxSOC_Actual])).STY(&amp;quot;geplant&amp;quot;,&amp;quot;font-size:12px;;position:absolute;;top:3px;;left:25px&amp;quot;).&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;.widget([$SELF:SpeicherMaxSOC_Actual],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Kontrolle&amp;lt;dd&amp;gt;aktiviert / läuft&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMiddayControlActive],&amp;quot;uzsuToggle,Aus,An&amp;quot;) | widget([$SELF:SpeicherMiddayControlRunning],&amp;quot;uzsuToggle,Aus,An&amp;quot;)|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;Mittags Limits&amp;lt;dd&amp;gt;Inverter_Max_Power / Laden nicht vor / Start /Stop&amp;lt;br&amp;gt;MaxSOC morgens / Power morgens / Power mittags&amp;lt;/dd&amp;gt;&amp;quot; | widget([$SELF:SpeicherMidday_Inverter_Max_Power],&amp;quot;selectnumbers,1000,250,15000,0,lin&amp;quot;).&amp;quot;W&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:SpeicherMidday_MaxSOC],&amp;quot;selectnumbers,5,1,100,0,lin&amp;quot;).&amp;quot;%&amp;quot; | widget([$SELF:SpeicherMidday_NotBefore],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_morning],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_start],&amp;quot;time&amp;quot;).widget([$SELF:SpeicherMidday_MaxChargePowerAbs_midday],&amp;quot;selectnumbers,0,100,4700,0,lin&amp;quot;).&amp;quot;W&amp;quot; | widget([WR_ctl:Yield_fc0_middayhigh_stop],&amp;quot;time&amp;quot;).([$SELF:SpeicherMidday_MaxChargePowerAbs_midday] == 0)?&amp;quot;dynamisch&amp;quot;:&amp;quot;&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
|&amp;quot;MinSOC Steuerung&amp;lt;dd&amp;gt;fc1_Limit / Winter | Sommer /aktuell&amp;lt;/dd&amp;gt;&amp;quot;|\&lt;br /&gt;
 FUNC_Status([WR_ctl:Yield_fc1_day],[$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;red&amp;quot;,&amp;quot;&amp;lt;&amp;quot;,0,0,([$SELF:SpeicherMinSOC_fc1_Limit]-1),&amp;quot;green&amp;quot;,&amp;quot;&amp;gt;=&amp;quot;).widget([$SELF:SpeicherMinSOC_fc1_Limit],&amp;quot;selectnumbers,2000,1000,40000,0,lin&amp;quot;).&amp;quot;wh&amp;quot; |\&lt;br /&gt;
 widget([$SELF:SpeicherMinSOC_Winter],&amp;quot;selectnumbers,10,1,30,0,lin&amp;quot;).widget([$SELF:SpeicherMinSOC_Sommer],&amp;quot;selectnumbers,5,1,10,0,lin&amp;quot;).&amp;quot;%&amp;quot; |&amp;quot;&amp;quot;|[WR_1_API:Battery_InternControl_MinSoc].&amp;quot; %&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1_ExternControl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherCmdRepeatActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherCmdRepeatRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-11 17:23:40 SpeicherDcPowerAbs 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:13 SpeicherEntladung Automatik&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherExternTrigger none&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:26 SpeicherMaxSOCControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOCControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 SpeicherMaxSOC_Actual 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMaxSOC_DayBefore 100&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_MinSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 08:10:03 SpeicherMaxSOC_MinSOC_Time NULL&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:38:43 SpeicherMaxSOC_fc1_Limit 30000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:27 SpeicherMiddayControlActive An&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-28 18:54:06 SpeicherMiddayControlRunning Aus&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:12 SpeicherMidday_Inverter_Max_Power 9000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-08 11:21:31 SpeicherMidday_MaxChargePowerAbs_midday 0&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:31 SpeicherMidday_MaxChargePowerAbs_morning 450&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:39:28 SpeicherMidday_MaxSOC 30&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-03 09:21:27 SpeicherMidday_NotBefore 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 18:45:27 SpeicherMinSOC_Sommer 5&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:42:54 SpeicherMinSOC_Winter 20&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-15 08:04:40 SpeicherMinSOC_fc1_Limit 16000&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-02-28 14:49:05 SpeicherTrigger entladen&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 16:10:24 SpeicherZeitEnde 19:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2021-12-03 10:41:25 SpeicherZeitStart 09:00&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 WB_1_smart_laden_before ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1 ---&lt;br /&gt;
setstate WR_1_Speicher_1_ExternControl 2022-03-29 14:33:58 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kostal Smart Energy Manager (KSEM) (Modbus/TCP)===&lt;br /&gt;
Sollte man mehrere AC Quellen im Haus haben werden die Messwerte benötigt, um den Hausverbrauch richtig zu berechnen.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;&#039;&#039;&#039;disable 1&#039;&#039;&#039;&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Um den ModBus am KSEM zu nutzen muss man im ModBus Menü die Option &amp;quot;Slave&amp;quot; aktivieren.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Das Device wurde umbenannt, um es besser in die gesamt Implementierung einzugliedern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- WR , es wird vom Wechselrichter benötigt und sortiert sich im FHEM Web auch dort ein.&lt;br /&gt;
- 0  , es wird von mehreren Geräten benötig, was z.B. auch eine Wallbox sein kann. WR_[1|2] könnte bedeuten, dass es nur von diesem Gerät benötigt wird.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bei einer Schwarm Installation steuert der KSEM mehrere Wechselrichter bezüglich der 70% Regelung. Eine Wallbox benötigt ebenfalls eine Verbindung, wenn nur mit Überschuss geladen werden soll.&lt;br /&gt;
Auch wenn der KSEM im FHEM auf disable 1 steht ist er aktiv und steuert die Wechselrichter und Wallboxen. Es bedeutet nur, dass die Werte nicht zusätzlich im Fhem eingelesen werden. Der Plenticore bereitet die Daten bereits selber auf und liefert diese im WR_1 Device per ModBus bereits mit.&lt;br /&gt;
Da es beim Plenticore ein Problem mit den Statistiken im Schwarm gibt wird das Device WR_0_KSEM nun aktiv verwendet. Durch das Device PV_Schedule werden die Werte Active_energy[+|-] ins Device WR_1_API übertragen und bilden die initial Werte für die Day/Month/Year Statistiken.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_0_KSEM ModbusAttr 1 60 192.168.178.xyz:502 TCP&lt;br /&gt;
attr WR_0_KSEM DbLogExclude .*&lt;br /&gt;
attr WR_0_KSEM DbLogInclude Active_energy.*&lt;br /&gt;
attr WR_0_KSEM alias WR_0_KSEM&lt;br /&gt;
attr WR_0_KSEM comment Version 2021.04.07 12:00\&lt;br /&gt;
Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\&lt;br /&gt;
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\&lt;br /&gt;
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\&lt;br /&gt;
\&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\&lt;br /&gt;
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\&lt;br /&gt;
\&lt;br /&gt;
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
attr WR_0_KSEM dev-h-defPoll 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr WR_0_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr WR_0_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr WR_0_KSEM disable 0&lt;br /&gt;
attr WR_0_KSEM event-on-change-reading Active_energy.*,M_AC_Current_.*&lt;br /&gt;
attr WR_0_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr WR_0_KSEM icon measure_power&lt;br /&gt;
attr WR_0_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr WR_0_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr WR_0_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr WR_0_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr WR_0_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40075-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr WR_0_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr WR_0_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr WR_0_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr WR_0_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40084-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr WR_0_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40086-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40087-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr WR_0_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr WR_0_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr WR_0_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr WR_0_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40091-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40096-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr WR_0_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr WR_0_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr WR_0_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr WR_0_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40101-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr WR_0_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr WR_0_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr WR_0_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr WR_0_KSEM obj-h40106-type INT16&lt;br /&gt;
attr WR_0_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr WR_0_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr WR_0_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr WR_0_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr WR_0_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr WR_0_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr WR_0_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr WR_0_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr WR_0_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr WR_0_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr WR_0_KSEM obj-h512-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr WR_0_KSEM obj-h512-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h516-format %.0f&lt;br /&gt;
attr WR_0_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr WR_0_KSEM obj-h516-type UINT64&lt;br /&gt;
attr WR_0_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr WR_0_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr WR_0_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr WR_0_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr WR_0_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr WR_0_KSEM obj-h8196-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr WR_0_KSEM obj-h8212-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr WR_0_KSEM obj-h8228-type STR32&lt;br /&gt;
attr WR_0_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr WR_0_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr WR_0_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_0_KSEM sortby 140&lt;br /&gt;
attr WR_0_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr WR_0_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===BYD HV Speicher (mit HTTPMOD)===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort wird mit KeyValue() (siehe oben) verwaltet.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Der BYD HV Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
 - Die erste Abfrage führt das Login durch&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num *&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
&lt;br /&gt;
======KeyValue() speichern======&lt;br /&gt;
Die Funktion befindet sich in der 99_myUtils und kann auch direkt in der Commandline aufgerufen werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
Syntax für die Commandline im FHEM {KeyValue(&amp;quot;[read|store]&amp;quot;,&amp;quot;PW_&amp;lt;device&amp;gt;_&amp;lt;key&amp;gt;&amp;quot;,&amp;quot;&amp;lt;password&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;store&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;,&amp;quot;&amp;lt;passwort&amp;gt;&amp;quot;)}&lt;br /&gt;
{KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition WR_1_Speicher_1 (BYD HV)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod WR_1_Speicher_1 HTTPMOD http://%IP-WR_1_Speicher_1%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr WR_1_Speicher_1 DbLogExclude .*&lt;br /&gt;
attr WR_1_Speicher_1 DbLogInclude BatteryInformation_TotalVoltage,BatteryInformation_SOC,BatteryInformation_SOC,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 authRetries 1&lt;br /&gt;
attr WR_1_Speicher_1 comment Version 2021.04.07 12:00&lt;br /&gt;
attr WR_1_Speicher_1 dontRequeueAfterAuth 0&lt;br /&gt;
attr WR_1_Speicher_1 enableControlSet 0&lt;br /&gt;
attr WR_1_Speicher_1 enableCookies 1&lt;br /&gt;
attr WR_1_Speicher_1 event-on-change-reading auth_.*,Battery.*_.*,Device.*_.*,Installation.*_.*,Array_.*,Statistic_GeneralInformation_Total.*&lt;br /&gt;
attr WR_1_Speicher_1 event-on-update-reading Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr WR_1_Speicher_1 get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr WR_1_Speicher_1 get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr WR_1_Speicher_1 get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr WR_1_Speicher_1 get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr WR_1_Speicher_1 get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr WR_1_Speicher_1 get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr WR_1_Speicher_1 get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr WR_1_Speicher_1 get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr WR_1_Speicher_1 get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr WR_1_Speicher_1 get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr WR_1_Speicher_1 get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr WR_1_Speicher_1 get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr WR_1_Speicher_1 get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr WR_1_Speicher_1 get01-16Name Array_Main_Current&lt;br /&gt;
attr WR_1_Speicher_1 get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr WR_1_Speicher_1 get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr WR_1_Speicher_1 get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr WR_1_Speicher_1 get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr WR_1_Speicher_1 get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr WR_1_Speicher_1 get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr WR_1_Speicher_1 get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr WR_1_Speicher_1 get01-22Name Array_Main_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr WR_1_Speicher_1 get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr WR_1_Speicher_1 get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get01-73Name Array_Main_Power&lt;br /&gt;
attr WR_1_Speicher_1 get01-80Name Array_Series_Battery&lt;br /&gt;
attr WR_1_Speicher_1 get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr WR_1_Speicher_1 get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr WR_1_Speicher_1 get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr WR_1_Speicher_1 get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get01MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get01Name RunData&lt;br /&gt;
attr WR_1_Speicher_1 get01RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr WR_1_Speicher_1 get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr WR_1_Speicher_1 get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr WR_1_Speicher_1 get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr WR_1_Speicher_1 get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr WR_1_Speicher_1 get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get02MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get02Name StatisticInformation&lt;br /&gt;
attr WR_1_Speicher_1 get02RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get02URL http://%IP-WR_1_Speicher_1%/asp/StatisticInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr WR_1_Speicher_1 get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr WR_1_Speicher_1 get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr WR_1_Speicher_1 get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr WR_1_Speicher_1 get03Name DeviceInformation&lt;br /&gt;
attr WR_1_Speicher_1 get03RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr WR_1_Speicher_1 get03URL http://%IP-WR_1_Speicher_1%/asp/DeviceInformation.asp&lt;br /&gt;
attr WR_1_Speicher_1 get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr WR_1_Speicher_1 get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr WR_1_Speicher_1 get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr WR_1_Speicher_1 get04-37Name BatteryInformation_Power&lt;br /&gt;
attr WR_1_Speicher_1 get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr WR_1_Speicher_1 get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr WR_1_Speicher_1 get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr WR_1_Speicher_1 get04-9Name BatteryInformation_Current&lt;br /&gt;
attr WR_1_Speicher_1 get04DeleteIfUnmatched 1&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAge 900&lt;br /&gt;
attr WR_1_Speicher_1 get04MaxAgeReplacementMode delete&lt;br /&gt;
attr WR_1_Speicher_1 get04Name BatteryInformation&lt;br /&gt;
attr WR_1_Speicher_1 get04RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr WR_1_Speicher_1 get04URL http://%IP-WR_1_Speicher_1%/asp/Home.asp&lt;br /&gt;
attr WR_1_Speicher_1 get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr WR_1_Speicher_1 get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr WR_1_Speicher_1 get05Name InstallationConfig&lt;br /&gt;
attr WR_1_Speicher_1 get05RegOpt g&lt;br /&gt;
attr WR_1_Speicher_1 get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr WR_1_Speicher_1 get05URL http://%IP-WR_1_Speicher_1%/asp/UserInfo.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Data ArrayNum=1&amp;amp;SeriesBatteryNum=4&lt;br /&gt;
attr WR_1_Speicher_1 get10Header01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 get10Header02 Referer: http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 get10Header03 Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
attr WR_1_Speicher_1 get10Header04 Accept: text/html,application/xhtml+xml,application/xml&lt;br /&gt;
attr WR_1_Speicher_1 get10Name Test_Array&lt;br /&gt;
attr WR_1_Speicher_1 get10URL http://%IP-WR_1_Speicher_1%/goform/SetRunData&lt;br /&gt;
attr WR_1_Speicher_1 getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 group PV Eigenverbrauch&lt;br /&gt;
attr WR_1_Speicher_1 handleRedirects 1&lt;br /&gt;
attr WR_1_Speicher_1 httpVersion 1.1&lt;br /&gt;
attr WR_1_Speicher_1 icon measure_battery_100&lt;br /&gt;
attr WR_1_Speicher_1 reAuthRegex Unauthorized&lt;br /&gt;
attr WR_1_Speicher_1 reading01Name auth_qop&lt;br /&gt;
attr WR_1_Speicher_1 reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Name auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Name auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Name auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Regex %IP-WR_1_Speicher_1%&lt;br /&gt;
attr WR_1_Speicher_1 replacement01Value ReadingsVal(&amp;quot;WR_1_config&amp;quot;,&amp;quot;IP-WR_1_Speicher_1&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Regex %auth_realm%&lt;br /&gt;
attr WR_1_Speicher_1 replacement03Value auth_realm&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Regex %auth_nonce%&lt;br /&gt;
attr WR_1_Speicher_1 replacement04Value auth_nonce&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Mode reading&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Regex %auth_opaque%&lt;br /&gt;
attr WR_1_Speicher_1 replacement05Value auth_opaque&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Mode expression&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Regex %auth_response%&lt;br /&gt;
attr WR_1_Speicher_1 replacement06Value {my $NAME=&amp;quot;WR_1_Speicher_1&amp;quot;;;my $pw=KeyValue(&amp;quot;read&amp;quot;,&amp;quot;PW_BYD_Status_installer&amp;quot;);; $pw =~ &#039;&amp;quot;&#039;.s/@/\\@/g.&#039;&amp;quot;&#039;;; md5_hex(md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.$pw).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:00000001:d789ea5b7e9a2377:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;));;}&lt;br /&gt;
attr WR_1_Speicher_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr WR_1_Speicher_1 showBody 0&lt;br /&gt;
attr WR_1_Speicher_1 showError 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid01ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid01URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sid02Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=&amp;quot;MD5&amp;quot;, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=&amp;quot;00000001&amp;quot;, cnonce=&amp;quot;d789ea5b7e9a2377&amp;quot;&lt;br /&gt;
attr WR_1_Speicher_1 sid02ParseResponse 1&lt;br /&gt;
attr WR_1_Speicher_1 sid02URL http://%IP-WR_1_Speicher_1%/asp/RunData.asp&lt;br /&gt;
attr WR_1_Speicher_1 sortby 121&lt;br /&gt;
attr WR_1_Speicher_1 stateFormat {sprintf(&amp;quot;Total_Charge_Energy: %.0f kWh&amp;lt;br&amp;gt;Total_Efficiency: %.1f %% Battery_EM_State: %s&amp;quot;, ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal($name,&amp;quot;Statistic_GeneralInformation_Total_Efficiency&amp;quot;,&amp;quot;0&amp;quot;), ReadingsVal(&amp;quot;WR_1_API&amp;quot;,&amp;quot;Battery_EM_State&amp;quot;,&amp;quot;&amp;quot;))}&lt;br /&gt;
attr WR_1_Speicher_1 userReadings Statistic_SpecificInformation_00_Date:Statistic_SpecificInformation_05_EndTime.* { CommandDeleteReading(undef, $NAME.&amp;quot; .*-.*&amp;quot;);;;; localtime()},\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Difference_Charge_Energy:Statistic_GeneralInformation_Total_Charge_Energy.*  {ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0) - ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_GeneralInformation_Total_Efficiency:Statistic_GeneralInformation_Total_Charge_Energy.*  {round(((ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Discharge_Energy&amp;quot;,0)+((ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Act_state_of_charge&amp;quot;,0)/100)*11)) / ReadingsVal($NAME,&amp;quot;Statistic_GeneralInformation_Total_Charge_Energy&amp;quot;,0))*100 , 2)}&lt;br /&gt;
attr WR_1_Speicher_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Device Übersicht mit Hilfen zur Orientierung==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Device            über Device      Hardware   Protokoll Netzwerk               Informationen&lt;br /&gt;
&lt;br /&gt;
WR_0_KSEM         WR_1             KSEM       MODBUS    LAN                    Messwerte vom Netzanschlusspunkt&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Notwendig, wenn ein Speicher am Plenticore betrieben wird&lt;br /&gt;
&lt;br /&gt;
WR_1                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte, teilweise Speicher Informationen&lt;br /&gt;
WR_1_API                                      HTTPMOD   LAN                    Statistiken, Speichersteuerung und Informationen&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1                    BYD HV     HTTPMOD   LAN/WLAN               Speicher Details, auch über einzelne Zellen. Das kann man nur für den alten BYD HV verwenden.&lt;br /&gt;
                  WR_1                        rs485     4 Draht zum WR         Verwendet von Plenticore zur Steuerung des Speichers&lt;br /&gt;
&lt;br /&gt;
WR_2                               Plenticore MODBUS    LAN                    Messwerte und berechnete Werte. Achtung, im Schwarm hat nur der Master WR einen Speicher.&lt;br /&gt;
WR_2_API                                      HTTPMOD   LAN                    Statistiken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FHEM Steuerung                                MODBUS    LAN                    Laufende Informationen im Minuten Takt&lt;br /&gt;
                                              HTTPMOD   LAN                    Abfragen und Steuerung einzelner Devices&lt;br /&gt;
&lt;br /&gt;
PV_Schedule                                   DOIF                             Startet regelmäßige Aktionen&lt;br /&gt;
&lt;br /&gt;
   1 Stündlich &lt;br /&gt;
   1.1 WR_2_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen; die Reihenfolge ist auch wichtig!&lt;br /&gt;
   1.2 WR_1_API 20_Statistic_EnergyFlow                                          Statistiken vom Plenticore abholen&lt;br /&gt;
&lt;br /&gt;
   2 Stündlich von 07:00 bis 20:00&lt;br /&gt;
   &#039;&#039;2.1 WR_1_config module_1_covered                                              Schnee auf den Modulen (noch in der Entwicklungsphase)&lt;br /&gt;
   2.2 Solar_forecast() für fc0                                                  Aktualisieren der fc0 Prognose&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   3 zweimal am Tag&lt;br /&gt;
   &#039;&#039;3.1 Solar_forecast() für fc1                                                  Aktualisieren der fc1 Prognose&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   4 alle 5 Minuten&lt;br /&gt;
   4.1 WR_2_API 04_auth_me                                                       Aktualisieren der Bilanz (es wird ein Event erzeugt)&lt;br /&gt;
   4.2 WR_1_API 04_auth_me                                                       Der Master Wechselrichter kommt zum Schluss, damit die SW_* readings auch von anderen&lt;br /&gt;
                                                                                 Wechselrichtern die richtigen Werte haben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;WR_*_config                                   DUMMY                            Konfiguration für Strings,Ausrichtung,Nennleistung,IP-Adressen,Forecast&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 DOIF                             Externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    1 Stündlich&lt;br /&gt;
&lt;br /&gt;
    1.1 WR_1_API 21_Battery_Information                                        Allgemeine Informationen&lt;br /&gt;
                    Battery_Info_SoC,&lt;br /&gt;
                    Battery_Info_WorkCapacity&lt;br /&gt;
    1.2 WR_1_API 22_Battery_InternControl                                      Speicher Information der Internen Steuerung&lt;br /&gt;
                    Battery_InternControl_MinSoc,&lt;br /&gt;
                    Battery_InternControl_MinHomeConsumption&lt;br /&gt;
    1.3 WR_1_API 23_Battery_ExternControl                                      Speicher Information der Externen Steuerung&lt;br /&gt;
    1.4 WR_1_API 25_Battery_EM_State                                           Speicher Status z.B. &amp;quot;Normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    2 Unterschreitung des MinSOC im Winter&lt;br /&gt;
    2.1 smart_laden                                                            PV Überschuss wird in Batterie geladen. Keine Entladung&lt;br /&gt;
    2.2 WR_1_Speicher_1_ExternControl ExternTrigger gesperrt                   Batterie ExternTrigger, Entlademodus gesperrt . Die Zeit Steuerung wird verriegelt&lt;br /&gt;
&lt;br /&gt;
    3 Freigabe zur Entladung im Winter&lt;br /&gt;
    3.1 bei überschreiten von SOC 90%                                          Sobald der Speicher gut gefüllt ist oder&lt;br /&gt;
             WR_1_API:Battery_Info_SoC&lt;br /&gt;
    3.2 Bei Zeitsteuerung und guter Prognose mit SOC 40%                       bereits vorher, weil der Tarif teuer ist&lt;br /&gt;
&lt;br /&gt;
    4 Speicher Freigabe bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    5 Speicher sperren  bei Trigger oder Zeit Steuerung                        Dieses cmd_ löst die Abhängigkeiten von Zeit und Trigger auf&lt;br /&gt;
&lt;br /&gt;
    6 Wiederhole alle 180s die Kommandos der ExternControl Steuerung           Wenn keine Wiederholung erfolgt geht der Plenticore wieder auf die interne Steuerung&lt;br /&gt;
    6.1 WR_1_Speicher_1_ExternControl:SpeicherMiddayControlActive              wird durchlaufen, wenn der Forecast eine z.B. 70% Überschreitung erkannt hat und&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxSOC               begrenzt dann morgens den MaxSOC&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_midday     und den MaxChargePowerAbs&lt;br /&gt;
             WR_1_Speicher_1_ExternControl:SpeicherMidday_MaxChargePowerAbs_morning    für morgens und mittags&lt;br /&gt;
    6.2 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Wenn morgens der Speicher zu voll war, wird der MaxSOC bis abends begrenzt&lt;br /&gt;
    6.3 WR_1:Solar_middayhigh_fc0_start &amp;lt;&amp;gt; WR_1:Solar_middayhigh_fc0_stop      Das Laden wird mit voller Leistung freigegeben&lt;br /&gt;
    6.4 nach Ablauf von WR_1:Solar_middayhigh_fc0_stop                         Die Midday Steuerung wird abgeschaltet, es wird normal weiter geladen, bis MaxSOC erreicht ist&lt;br /&gt;
    6.5 WR_1_Speicher_1_ExternControl:SpeicherMaxSOC                           Batterie MaxSOC halten, der Default ist 100%&lt;br /&gt;
&lt;br /&gt;
    7 Initialisierung der externen Speichersteuerung&lt;br /&gt;
    7.1 Ist morgens der Speicher zu voll                                       Wenn der Speicher morgens voller als 3x MinSOC ist wird MaxSOC gesetzt&lt;br /&gt;
    7.2 Wenn eine Überschreitung der 70% erwartet wird                         Aktivierung der Midday Steuerung&lt;br /&gt;
&lt;br /&gt;
    8 Zurücksetzen der externen Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
    9 Umschaltung des MinSOC wenn zu wenig Leistung erwartet wird              Schaltet im Herbst/Winter den MinSOC auf 20%&lt;br /&gt;
&lt;br /&gt;
   10 Umschaltung des MinSoc wenn viel Leistung erwartet wir                   Setzt den MinSOC wieder im Frühling/Sommer auf 5%&lt;br /&gt;
&lt;br /&gt;
   11 WR_1_Speicher_1 Status aktualisieren                                     Nur beim BYD HV, Abfrage der Speicher Detailinformationen. Kann einfach entfernt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WR_1_Speicher_1_ExternControl                 readings                         Konfiguration für die externe Speichersteuerung&lt;br /&gt;
&lt;br /&gt;
   ExternTrigger none                                                          Wird automatisch gesetzt und dient der Verriegelung im WR_1_Speicher_1_ExternControl&lt;br /&gt;
                                                                               Zustände: frei/gesperrt/none&lt;br /&gt;
   SpeicherCmdRepeatActive      [An|Aus]                                       An/Aus Trigger für WR_1_Speicher_1_ExternControl, aktiviert die Kommandowiederholung&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherEntladung                                                           Steuert den Modus der externen Speichersteuerung&lt;br /&gt;
                                                                               Zustände:&lt;br /&gt;
                                                                                 Automatik - MinSOC Steuerung Sommer/Winter&lt;br /&gt;
                                                                                 Zeit      - z.B. bei Tarifsteuerung. Zeiten werden über zusätzliche DOIF&lt;br /&gt;
                                                                                             oder WeekdayTimer gesetzt&lt;br /&gt;
                                                                                 Trigger   - Ein beliebiger Mechanismus z.B. DOIF steuert den Speicher&lt;br /&gt;
&lt;br /&gt;
   SpeicherMaxSOCControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMaxSOCControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMaxSOC_Actual      100                                              Wird im WR_1_Speicher_1_ExternControl cmd_7 berechnet, wenn der Speicher morgens zuviel Ladung hat&lt;br /&gt;
   SpeicherMaxSOC_DayBefore    xx                                              Das ist der letzte berechnete Wert, damit sich die Berechnung langsam einem Optimum nähern kann&lt;br /&gt;
   SpeicherMaxSOC_fc1_Limit 30000                                              Hier einen Wert setzen, bei dem der Speicher über Nacht bis morgens gereicht hat.&lt;br /&gt;
                                                                               Damit wird dann der Übergang vom Winter zum Frühjahr erkannt.&lt;br /&gt;
   SpeicherMiddayControlActive  [An|Aus]                                       Wird von Solar_forecast() gesetzt, wenn der fc0 über WR_1:Inverter_Max_Power (70% Regel) liegt&lt;br /&gt;
   SpeicherMiddayControlRunning [An|Aus]                                       Das reading signalisiert den aktuellen Laufzeitstatus&lt;br /&gt;
   SpeicherMidday_Inverter_Max_Power        8500                               Manuelles überschreiben für WR_1:Inverter_Max_Power, wenn man kontrollierter den Tag über laden möchte&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_midday  1000                               Begrenzung der Ladeleistung am Mittag, damit nicht zu schnell geladen wird.&lt;br /&gt;
                                                                               Steht der Wert auf 0 wird dynamisch während der Laufzeit ein Wert berechnet.&lt;br /&gt;
   SpeicherMidday_MaxChargePowerAbs_morning  450                               Begrenzung der Ladeleistung am Vormittag, damit Mittags genug Platz im Speicher ist&lt;br /&gt;
   SpeicherMidday_MaxSOC 30                                                    Limitierung des Speichers um Mittags genug Platz zu haben&lt;br /&gt;
   SpeicherMinSOC_Sommer 5                                                     Sommer MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_Winter 20                                                    Winter MinSOC von Kostal vorgegeben&lt;br /&gt;
   SpeicherMinSOC_fc1_Limit 14000                                              Wenn im Herbst/Winter der Forecast zu schlecht wird muss dieser Wert auf die Anlage&lt;br /&gt;
                                                                               angepasst werden. Das signalisiert die Winter Zeit&lt;br /&gt;
   SpeicherTrigger none                                                        entladen/gesperrt/none wird über WR_1_Speicher_1_ExternControl gesetzt&lt;br /&gt;
   SpeicherZeitEnde 16:00                                                      Die Zeiten geben das Entlade Fenster an und werden durch weitere DOIF oder WeekdayTimer gesetzt&lt;br /&gt;
   SpeicherZeitStart 07:00                                                     Dies kann zur Tarifsteuerung verwendet werden, oder um ein Entladung zeitlich zu verschieben&lt;br /&gt;
                                                                               Das Zeitfenster kann durch den MinSOC Schutz im Winter veriegelt sein.&lt;br /&gt;
&lt;br /&gt;
   Beispiele:&lt;br /&gt;
&lt;br /&gt;
   1 SpeicherEntladung Automatik&lt;br /&gt;
     Nur grundlegende Steuerungen erfolgen automatisch.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC                                   Schützt den Speicher vor einer Notladung im Winter&lt;br /&gt;
      - smart_laden                                                            Sorgt dafür, das der Speicher im Winter nicht ständig geladen und wieder entladen wird&lt;br /&gt;
      - laden_beendet                                                          Gibt den Speicher nach dem smart_laden wieder frei&lt;br /&gt;
&lt;br /&gt;
   2 SpeicherEntladung Zeit&lt;br /&gt;
     Zeitsteuerung für laden/entladen&lt;br /&gt;
      - WR_1_Speicher_1_ExternControl:SpeicherZeitEnde/SpeicherZeitStart       Die Start/Ende Zeiten müssen gesetzt werden, dies muss über weitere DOIF oder WeekdayTimer erfolgen.&lt;br /&gt;
      - Sommer/Winter Umschaltung des MinSOC&lt;br /&gt;
      - smart_laden&lt;br /&gt;
      - laden_beendet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wenn man mal etwas umbenennen möchte==&lt;br /&gt;
Es kommt immer wieder vor, dass man ein Device oder den Namen eines readings umbenennen möchte. Dies hat natürlich Auswirkungen auf andere Devices und auch auf die bisherigen Daten in der DbLog. Hier sollen dann jetzt Hilfestellungen gesammelt werden.&lt;br /&gt;
===Allgemeine Hilfestellungen===&lt;br /&gt;
&#039;&#039;&#039;Es sollte immer vorher eine Datensicherung gemacht werden!&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
Den Device Namen ändert man am Besten mit einem &amp;quot;rename&amp;quot;.&lt;br /&gt;
Damit nichts vergessen wird ruft man den RAW Editor auf und kann dann mit der Suchfunktion des Browsers nach dem zu ändernden Text suchen.&lt;br /&gt;
Wenn alle Devices im ersten Durchlauf geändert wurden und man meint man wäre fertig, dann durchsucht man am besten nochmal die fhem.cfg . Sollten dort noch alte Namen vorhanden sein, kann man erkennen in welchem Device das ist und dieses dann in der Fhem Oberfläche korrigieren.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bitte nicht in der fhem.cfg Änderungen vornehmen! Dort nur zur Kontrolle suchen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Ein Device umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Das ist schnell gemacht, indem man in der Fhem commandline ein &amp;quot;rename &amp;lt;Device&amp;gt; &amp;lt;neues Device&amp;gt;&amp;quot; macht.&lt;br /&gt;
Es ist auch möglich das alte Device mit &amp;quot;disable 1&amp;quot; zu deaktivieren und dann einfach ein komplett neues z.B. aus dem Wiki zu definieren.&lt;br /&gt;
Das alte Device kann dann später gelöscht werden, sobald das neu richtig läuft. In der datenbank kann man die alten Werte dann auch wieder dem neuen Device zuordnen.&lt;br /&gt;
Als nächstes haben viele Devices noch ein Attribut &amp;quot;alias&amp;quot;, das meistens den selben Namen wie das Device beinhaltet.&lt;br /&gt;
Ein Device Name kann auch in anderen Attributen als Variable verwendet worden sein. Das ist zu prüfen.&lt;br /&gt;
Nun werden alle neuen, aktualisierten readings unter dem neuen Device Namen in die Datenbank geschrieben.&lt;br /&gt;
Die bisherigen Log Einträge müssen nun noch dem neuen Device zugeordnet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Ein reading umbenennen===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Dies geschieht innerhalb des Devices, indem man das Attribut, dass das reading erzeugt ändert und den neuen Namen einträgt.&lt;br /&gt;
Bei der nächsten Aktualisierung erscheint dann ein zweites reading mit dem neuen Namen.&lt;br /&gt;
Der neue Name muss dann noch an allen Stellen innerhalb des Devices eingetragen werden, Das kann im userReading, stateFormat oder auch in anderen Attributen der Fall sein.&lt;br /&gt;
Soll dieses Reading gelogged werden, ist &amp;quot;DbLogInclude&amp;quot; zu prüfen. Der alte Name kann raus und der neue muss rein, oder die RegEx muss geändert werden.&lt;br /&gt;
Zum Schluss muss das alte reading noch entfernt werden, was mit &amp;quot;deletereading &amp;lt;Device&amp;gt; &amp;lt;alter reading Name&amp;gt;&amp;quot; erfolgen kann. Oft ist hier auch eine RegEx möglich.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog aufräumen===&lt;br /&gt;
Als kleine Vorabinformation möchte ich geben, dass es hierbei eventuell zu &#039;&#039;&#039;duplicate keys&#039;&#039;&#039; kommen kann. Dies rührt daher, dass eventuell der alte und der neue Namen parallel geloggt wurde. Schaut Euch hier die Daten an, welche Ihr behalten möchtet, oder ob Ihr wirklich z.B. das alte reading und SW_* braucht. Ab dem Zeitpunkt wo es parallel gelaufen ist, wäre dann eins (das alte) zu löschen.&lt;br /&gt;
&lt;br /&gt;
Beim Übergang zum Schwarm habe ich alle älteren Daten den neuen readings zugeordnet und momentan, ab diesem Zeitpunkt, beides gelogged.&lt;br /&gt;
&lt;br /&gt;
====An der Datenbank anmelden====&lt;br /&gt;
Dies kann man z.B. aus einer Terminal Session heraus machen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 192.168.178.xxx --port 3306 --database fhem -u fhemuser -p&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Alle Devices in der history anzeigen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Alle Devices in der history Tabelle&lt;br /&gt;
SELECT DEVICE FROM history&lt;br /&gt;
 GROUP BY DEVICE;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alle readings eines Devices anzeigen====&lt;br /&gt;
Mit einem SELECT kann man alle bisher aufgetretenen readings eines Devices über einen definierten Zeitraum anzeigen lassen.&lt;br /&gt;
Der Zeitraum ist mit &amp;quot;1 DAY&amp;quot; definiert, kann aber auch auf z.B. &amp;quot;1 MONTH&amp;quot; oder &amp;quot;2 MONTH&amp;quot; gesetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
SET @device = &#039;WR_1&#039;;&lt;br /&gt;
SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE&lt;br /&gt;
  FROM history t1&lt;br /&gt;
  INNER JOIN&lt;br /&gt;
   (SELECT max(TIMESTAMP) AS TIMESTAMP,DEVICE,READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE    = @device AND&lt;br /&gt;
            TIMESTAMP &amp;gt; NOW() - INTERVAL 1 DAY&lt;br /&gt;
      GROUP BY READING) x&lt;br /&gt;
  ON x.TIMESTAMP = t1.TIMESTAMP AND&lt;br /&gt;
     x.DEVICE    = t1.DEVICE    AND&lt;br /&gt;
     x.READING   = t1.READING;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Einträge eines DEVICE einem neuen DEVICE zuordnen====&lt;br /&gt;
In diesem Beispiel würde das alte DEVICE PV_1 dem neuen DEVICE WR_1 zugeordnet werden.&lt;br /&gt;
Im Anschluss müssten dann noch READING jeweils einem eventuell neuen READING Namen zu geordnet werden.&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    DEVICE    = &#039;PV_1&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Ein altes READING einem neuen READING Namen zuordnen====&lt;br /&gt;
Sehr wichtig ist &#039;&#039;&#039;&amp;quot;TIMESTAMP = TIMESTAMP&amp;quot;&#039;&#039;&#039;, da hierdurch der alte TIMESTAMP erhalten bleibt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE history&lt;br /&gt;
  SET&lt;br /&gt;
    TIMESTAMP = TIMESTAMP,&lt;br /&gt;
    READING   = &#039;Total_DC_PV_Energy_sumOfAllPVInputs&#039;&lt;br /&gt;
  WHERE&lt;br /&gt;
        DEVICE    = &#039;WR_1&#039;&lt;br /&gt;
    AND READING   = &#039;Total_DC_PV_Energy_(sumOfAllPVInputs)&#039;&lt;br /&gt;
    AND TIMESTAMP &amp;lt; &#039;2021-03-23 17:25:15&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Alles auf einmal====&lt;br /&gt;
Natürlich kann man die vorherigen UPDATE auch zusammenfassen, also DEVICE und READING in einem ändern. Das sollte aber nur machen, wer in SQL entsprechende Kenntnisse hat.&lt;br /&gt;
Die Umbenennung des DEVICE zum neuen DEVICE und anschließend die READING Namen ist der praktikabelste Weg.&lt;br /&gt;
&lt;br /&gt;
===Grafiken korrigieren===&lt;br /&gt;
====SVG====&lt;br /&gt;
In eventuellen SVGs die Device und reading Namen korrigieren&lt;br /&gt;
====Grafana====&lt;br /&gt;
In Grafana sind die SQL Abfragen ebenfalls zu korrigieren&lt;br /&gt;
&lt;br /&gt;
===Fhem Log===&lt;br /&gt;
Das Fhem Log ist nach jedem größeren Änderungsschritt zu sichten, da man hier ziemlich schnell vergessene Devices oder readings erkennen kann.&lt;br /&gt;
&lt;br /&gt;
==Timeing für die PV extra Funktionen==&lt;br /&gt;
=== AW Definition PV_Schedule (DOIF)===&lt;br /&gt;
Aufgrund der Komplexität wurde die Speichersteuerung aus diesem Device entfernt und im Device PV_1_Speicher_1_ExternControl ausgelagert.&lt;br /&gt;
Weitere Neuerungen sind die Bereitstellung eines Schnee Faktors pro String für die Solar_forecast() Funktion, was aber bitte als Versuch anzusehen ist.&lt;br /&gt;
Für den Vergleich mit dem Solar_Foracast Modul wird der Forecast zwei mal aufgerufen und einmal davon ins DWD_Forecast_Test geschrieben.&lt;br /&gt;
Diese Beispiele können natürlich einfach herausgelöscht werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
\&lt;br /&gt;
   (get WR_2_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
   (get WR_1_API 20_Statistic_EnergyFlow)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 5 und 21 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([05:00-21:00] and [:00])\&lt;br /&gt;
   ## Erste Versuche mit Schnee, wenn zuwenig Strom in den Modulen fließt wird ein Faktor von 0.1 gesetzt\&lt;br /&gt;
   ## WR_1_config forecast_factor_autocorrection muss auf 1 gesetzt sein, damit das berücksichtigt wird\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt;  8 &amp;amp;&amp;amp; $hour &amp;lt; 12)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_1_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_1&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_2_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC1&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 12 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_3_covered &amp;quot;.$y)})\&lt;br /&gt;
##   ({my $y=0;;;;my $x=ReadingsVal(&amp;quot;WR_2&amp;quot;,&amp;quot;Current_DC2&amp;quot;,1);;;;\&lt;br /&gt;
##     $y=($x &amp;gt;= 0 &amp;amp;&amp;amp; $x &amp;lt; 1 &amp;amp;&amp;amp; $hour &amp;gt; 14 &amp;amp;&amp;amp; $hour &amp;lt; 17)?0.1:1;;;;CommandSetReading(undef, &amp;quot;WR_1_config module_4_covered &amp;quot;.$y)})\&lt;br /&gt;
\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   ## Bei Schnee wurde der module_*_covered Faktor bereits am Vortag gesetzt.\&lt;br /&gt;
   ({Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
##   ({Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;DWD_Forecast_Test&amp;quot;,&amp;quot;Solar_forecast_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)})\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 regelmäßig die Bilanz aktualisieren, alle 5 Minuten außer um :00\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00])\&lt;br /&gt;
\&lt;br /&gt;
  (get WR_2_API 04_auth_me)\&lt;br /&gt;
  (get WR_1_API 04_auth_me)\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Jeden Morgen die Zählerstände aktualisieren, damit im Schwarm die Statistiken berechnet werden können\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([00:01])\&lt;br /&gt;
\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_FeedInGrid_Day [WR_0_KSEM:Active_energy-])   ## 6172\&lt;br /&gt;
  (setreading WR_1_API SW_Meter_init_Grid_Day [WR_0_KSEM:Active_energy+])         ## 4727\&lt;br /&gt;
\&lt;br /&gt;
 ({if ($mday eq 1)\&lt;br /&gt;
     {\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Month [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5707\&lt;br /&gt;
      fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Month [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 4717\&lt;br /&gt;
\&lt;br /&gt;
      if ($yday eq 0)\&lt;br /&gt;
        {\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_FeedInGrid_Year [WR_0_KSEM:Active_energy-]&amp;quot;);;   ## 5241\&lt;br /&gt;
         fhem(&amp;quot;setreading WR_1_API SW_Meter_init_Grid_Year [WR_0_KSEM:Active_energy+]&amp;quot;);;         ## 3517\&lt;br /&gt;
        }\&lt;br /&gt;
     }\&lt;br /&gt;
  }\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState WR Status|Forecast 0|Forecast 1|Bilanz refresh&lt;br /&gt;
attr PV_Schedule comment Version 2021.04.19 12:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0,3:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4&lt;br /&gt;
attr PV_Schedule webCmdLabel Statistic :Forecast_0 :Forecast_1 :Bilanz :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Energie Bilanz==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im WR_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions- und Verbrauchswerte liefern. Hierbei werden die momentan Werte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
===Erstellen von zusätzlichen Werten in der Datenbank===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist die wöchentliche Einspeisung ins Netz.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;defmod LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week comment Version 2020.10.21 11:14&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffAccept 15000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week reading Statistic_EnergyFeedInGrid_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week readingNameMap Statistic_EnergyFeedInGrid_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 1&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über PV_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_Statistic_Yield_Month_max_Month====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Löschen von nicht mehr benötigten Werten in der Datenbank===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen Trend erkennen lassen.&lt;br /&gt;
Wenn eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day reading Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_EnergyHomeBat_Day Werte, bis auf den maximal Wert des Tages.&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_EnergyHomePvSum_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.\&lt;br /&gt;
Aufruf mit: maxValue deleteOther&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day reading Statistic_EnergyHomePvSum_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day====&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day aggregation day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day comment Version 2020.10.30 18:30\&lt;br /&gt;
Löschen aller Statistic_TotalConsumption_Day Werte, bis auf den maximal Wert des Tages.\&lt;br /&gt;
Der aktuelle Tag bleibt noch erhalten.&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day device PV_1_API&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day reading Statistic_TotalConsumption_Day&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day timestamp_end current_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Timing für die Datenbank Einträge===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
====RAW Definition DB_Service_Schedule====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyFeedInGrid_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
\&lt;br /&gt;
## Wöchentliche Einträge mit löschen\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([02:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomeBat_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_EnergyHomePvSum_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
 (set LogDBRep_delete_Statistic_TotalConsumption_Day_max_Day maxValue deleteOther)\&lt;br /&gt;
&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,5,5:0,5,5&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2:cmd_3&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :wöchentlich Löschen :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose==&lt;br /&gt;
Bei der Leistungsprognose gibt es nun eine gravierende Veränderung. Die bisherige Leistungsprognose durch eine eigene Berechnung, die auf diversen Konfigurationsparametern basiert hat wurde vollständig durch eine KI_Prognose abgelöst. Die bisherige Implementierung wird nicht mehr weiter entwickelt und ist hier nur noch zu Dokumentationszwecke aufgeführt.&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose KI_Prognose==&lt;br /&gt;
Erstmalig wurde die [https://forum.fhem.de/index.php?msg=1268412 KI_Prognose hier im Forumsthread in vier Teil Posts] beschrieben. Im weiteren Thread sind auch noch Informationen dazu zu finden.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose - Grundgedanke===&lt;br /&gt;
Nun ist der Ansatz der KI eingezogen und meine Ergebnisse, von bisherigen Tests, sehen schon ziemlich gut aus.&lt;br /&gt;
&lt;br /&gt;
Der Grundgedanke ist, dass die Prognose keinerlei technischen Informationen über den Aufbau der PV-Anlage benötigt. Einzig allen der Ertrag der Anlage wird dabei in Bezug zu den Wetterdaten des jeweiligen Standortes gesetz, wobei die KI daraus Rückschlüsse zieht, wie bei ähnlichen Bedingungen der ertrag werden könnte. Je mehr vergleichbare Daten dazu zur Verfügung stehen, umso besser wird die Prognose.&lt;br /&gt;
&lt;br /&gt;
In der momentan implementierten Prognose besteht darüber hinaus ein Problem, das man die momentan erzeugte Leistung eigentlich mit der zu erwartenden Energieprognose vergleicht.&lt;br /&gt;
Beim neuen Ansatz wird nun versucht das mit zu korrigieren, was auch im Diagramm durch die Stufen Darstellung verdeutlicht wird.&lt;br /&gt;
&lt;br /&gt;
Die KI Prognose arbeitet nun über den Yield, den der Plenticore jede Stunde aktualisiert. Bei diesem Yield ist nun jedoch ein weiteres Problem, da der hybrid Wechselrichter natürlich auf der AC Seite den Yield angibt und somit das Laden des Speichers nicht aktuell mit zählt. Die Speicher Entladung wird später dann wiederum mit gerechnet, was die AC Yield Kurve dann sehr merkwürdig aussehen lässt. An dieser Problematik wurde auch bereits gearbeitet und das wird dann später nochmal erwähnt.&lt;br /&gt;
&lt;br /&gt;
Im Diagramm sieht man nun in blau den korrigierten Yield unter Berücksichtigung des Speichers und in diesem Beispiel Fall für eien gesamten Schwarm (ich habe zwei WR). Jede Stufe im Diagramm ist dann nun der Ertrag (Yield) der entsprechenden Stunde in kWh.&lt;br /&gt;
Zur Orientierung sieht man in gelb die AC Leistung in kW, gezeichnet aus den minütlichen Messwerten.&lt;br /&gt;
Die rosa Stufen sind dann nun endlich die Ertrags Prognose Werte aus der KI in kWh.&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 1 - DWD und Astro Daten sammeln===&lt;br /&gt;
Solltet Ihr später mit in diese Richtung gehen wollen, so macht es Sinn [b]schon jetzt die Wetterdaten für Euren Standort zu sammeln[/b], da diese die Grundlage bilden und im Anschluss mit dem korrigierten Ertrag in Verbindung gebracht werden. Alle im comment angegebenen DWD Werte werden später von der KI ausgewertet und müssen somit in der DbLog vorliegen. Je mehr DWD Daten von den letzten Jahren vorliegen, umso besser kann die KI Rückschlüsse ziehen. Sollten diese nicht da sein, so lernt das ganze langsam dazu.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition DWD_Forecast====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc.*_.*_Rad1h,fc.*_.*_TTT,fc.*_.*_FF,fc.*_.*_Neff,fc.*_.*_R101,fc.*_.*_RRS1c,fc.*_.*_DD,fc.*_.*_N,fc.*_.*_VV,fc.*_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2022.08.20 12:00\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
FF      : Windspeed\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc.*_.*_[Rad1h|TTT|FF|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,FF,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
Da die KI Prognose ja auch die Astro Daten für den Sonnenstand benötigt und dieser im Astro Device nicht als fc[0|1] vorliegt habe ich das Astro Device etwas modifiziert. In den userreadings werden dort die fc[0|1] Sonnenstände jetzt abgefragt und als readings eingetragen. Dies geschieht sobald es einen Event von ObsDate gibt, der einmal täglich kommen sollte. Somit beachtet auch die Änderung bei event-on-update-reading und beim DbLogInclude.&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz,fc.*_.*&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro event-on-update-reading ObsDate.*,fc.*_.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
attr Astro userReadings fc0_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime))},\&lt;br /&gt;
fc0_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime))},\&lt;br /&gt;
\&lt;br /&gt;
fc1_6_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAlt:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAlt&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_6_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 06:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_7_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 07:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_8_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 08:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_9_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 09:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_10_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 10:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_11_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 11:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_12_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 12:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_13_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 13:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_14_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 14:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_15_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 15:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_16_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 16:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_17_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 17:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_18_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 18:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_19_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 19:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_20_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 20:00:00&amp;quot;,localtime(time+1*24*60*60)))},\&lt;br /&gt;
fc1_21_SunAz:ObsDate.* {Astro_Get(undef,&amp;quot;Astro&amp;quot;,&amp;quot;text&amp;quot;,&amp;quot;SunAz&amp;quot;,POSIX::strftime(&amp;quot;%Y-%m-%d 21:00:00&amp;quot;,localtime(time+1*24*60*60)))}&lt;br /&gt;
attr Astro verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
Hier müsst Ihr Eure Position und Höhe eintragen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.xxxxx&lt;br /&gt;
attr global longitude 9.yyyyy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===KI Prognose Teil 2 - Vorbereitung der Daten===&lt;br /&gt;
In diesem Teil geht es darum die Daten aus der FHEM History so aufzubereiten, dass sie für die KI Prognose verwendbar wird. Das Daten Model der FHEM History ist in der Form nicht für diese Verarbeitung brauchbar und wird deshalb in eine neu Tabelle überführt. Bei der Gelegenheit wird einiges noch aufbereitet und insbesondere der yield des Plenticore mit Speicher korrigiert.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition dwd_load() MySQL Procedure====&lt;br /&gt;
Hier kommt nun die MySQL Procedure, die in der Datanbank hinterlegt wird. Dazu verwende ich z.B. die MySQL Workbench, wo dann die Procedure unter &amp;quot;Stored Precedures&amp;quot; auftaucht. Dies ermöglicht, dass man im FHEM DbRep Device nur diese eine Procedure aufrufen kann und nicht jedes einzelne SELECT zur Datenbank in einer separaten Session übermittelt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
CREATE DEFINER=`fhemuser`@`%` PROCEDURE `dwd_load`(IN var_date DATE, IN display char(10))&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;br /&gt;
SET @date:= var_date;&lt;br /&gt;
-- die alte Tabelle löschen&lt;br /&gt;
DROP TABLE IF EXISTS dwdfull;&lt;br /&gt;
&lt;br /&gt;
-- eine neue Tabelle anlegen&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `dwdfull` (&lt;br /&gt;
  `TIMESTAMP` datetime NOT NULL,&lt;br /&gt;
  `year`   int NOT NULL,&lt;br /&gt;
  `month`  int NOT NULL,&lt;br /&gt;
  `day`    int NOT NULL,&lt;br /&gt;
  `hour`   int NOT NULL,&lt;br /&gt;
  `TTT`    float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `DD`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `VV`     float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `N`      float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Neff`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `R101`   float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `RRS1c`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunD1`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `Rad1h`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAz`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `SunAlt` float  NOT NULL DEFAULT 0,&lt;br /&gt;
  `yield`  float  DEFAULT 0,&lt;br /&gt;
  `yield_max`  float  DEFAULT 0,&lt;br /&gt;
  `forecast`  float  NOT NULL DEFAULT 0,&lt;br /&gt;
  PRIMARY KEY (`TIMESTAMP`),&lt;br /&gt;
  INDEX (`TIMESTAMP`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=&#039;DWD Forecast&#039;;&lt;br /&gt;
&lt;br /&gt;
-- als erstes die Grundlegenden Daten mit Zeitstempeln erzeugen&lt;br /&gt;
-- Rad1h wird als erstes eingetragen&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc0 Rad1h ältere Werte eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                  AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
	 	       )&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
INSERT INTO dwdfull (TIMESTAMP, year, month ,day ,hour ,Rad1h)&lt;br /&gt;
   SELECT concat(t1.DATE, &amp;quot; &amp;quot;, LPAD(t1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          year(t1.DATE) AS year,&lt;br /&gt;
          month(t1.DATE) AS month,&lt;br /&gt;
          day(t1.DATE) AS day,&lt;br /&gt;
          t1.HOUR AS hour,&lt;br /&gt;
          t1.Rad1h&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- fc1 Rad1h Werte von morgen eintragen&lt;br /&gt;
      SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
             x1.DATE,&lt;br /&gt;
             x1.HOUR,&lt;br /&gt;
             h.VALUE AS Rad1h&lt;br /&gt;
      FROM history h&lt;br /&gt;
      INNER JOIN&lt;br /&gt;
        (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
                LPAD(REGEXP_SUBSTR(READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0) AS HOUR,&lt;br /&gt;
                max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                READING&lt;br /&gt;
         FROM history&lt;br /&gt;
         WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
           AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Rad1h&#039;&lt;br /&gt;
           AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
         GROUP BY READING,DATE,HOUR&lt;br /&gt;
	    ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
      ) t1&lt;br /&gt;
ON DUPLICATE KEY UPDATE&lt;br /&gt;
   Rad1h = t1.Rad1h&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Mit update alle weiteren Spalten füllen&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAz&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t2  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t2.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAz&lt;br /&gt;
  SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAz&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAz&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAz&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAz = t3.SunAz&lt;br /&gt;
;&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
             min(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING = &#039;SunAlt&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;gt;= 6&lt;br /&gt;
        AND hour(TIMESTAMP) &amp;lt;= 21&lt;br /&gt;
      GROUP BY READING,DATE,HOUR&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunAlt&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunAlt&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;Astro&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunAlt&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t3  USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunAlt = t3.SunAlt&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 SunD1&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS SunD1&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_SunD1&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t4 USING(TIMESTAMP)&lt;br /&gt;
SET tt.SunD1 = t4.SunD1&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 Neff&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS Neff&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_Neff&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.Neff = t5.Neff&lt;br /&gt;
;&lt;br /&gt;
   &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t6 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t6.VV&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 VV&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS VV&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_VV&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.VV = t5.VV&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t7 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t7.DD&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 DD&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS DD&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_DD&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.DD = t5.DD&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t8 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t8.TTT&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 TTT&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS TTT&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_TTT&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.TTT = t5.TTT&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t9 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t9.R101&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 R101&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS R101&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_R101&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.R101 = t5.R101&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t10 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t10.N&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 N&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS N&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_N&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.N = t5.N&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc0 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc0_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND (      TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
             OR    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
               AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
			)&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t11 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t11.RRS1c&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- fc1 RRS1c&lt;br /&gt;
   SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(REGEXP_SUBSTR(h.READING, &#039;[6-9]|1[0-9]|2[0-1]&#039;), 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
          h.VALUE AS RRS1c&lt;br /&gt;
   FROM history h&lt;br /&gt;
   INNER JOIN&lt;br /&gt;
     (SELECT date(DATE_ADD(TIMESTAMP,INTERVAL +1 DAY)) AS DATE,&lt;br /&gt;
             max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
             READING&lt;br /&gt;
      FROM history&lt;br /&gt;
      WHERE DEVICE = &#039;DWD_Forecast&#039;&lt;br /&gt;
        AND READING REGEXP &#039;fc1_([6-9]|1[0-9]|2[0-1])_RRS1c&#039;&lt;br /&gt;
        AND TIMESTAMP &amp;gt;= @date&lt;br /&gt;
      GROUP BY READING,DATE&lt;br /&gt;
	 ) x1 USING(TIMESTAMP,READING)&lt;br /&gt;
   ) t5 USING(TIMESTAMP)&lt;br /&gt;
SET tt.RRS1c = t5.RRS1c&lt;br /&gt;
;&lt;br /&gt;
 &lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield from Plenticore with Accu&lt;br /&gt;
   -- start left join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    left JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end left join&lt;br /&gt;
   &lt;br /&gt;
   UNION  -- for left and right join&lt;br /&gt;
&lt;br /&gt;
   -- start right join&lt;br /&gt;
   SELECT TIMESTAMP, &lt;br /&gt;
          WR.yield       AS WR,&lt;br /&gt;
          Speicher.yield AS Speicher,&lt;br /&gt;
          cast( -- validate yield&lt;br /&gt;
               if((Speicher.yield IS NULL),&lt;br /&gt;
                   WR.yield,&lt;br /&gt;
                   if((WR.yield IS NULL),Speicher.yield,WR.yield + Speicher.yield)&lt;br /&gt;
                 )&lt;br /&gt;
			AS DECIMAL(6)) AS yield&lt;br /&gt;
   FROM&lt;br /&gt;
     ( -- WR&lt;br /&gt;
        SELECT TIMESTAMP,&lt;br /&gt;
               if(t1.DELTA &amp;gt; 6,0,t1.DIFF) AS yield&lt;br /&gt;
        FROM&lt;br /&gt;
          (SELECT TIMESTAMP,READING,VALUE,&lt;br /&gt;
                  if(@diff = 0,0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                  @diff:=VALUE                                        AS curr_V,&lt;br /&gt;
                  TIMESTAMPDIFF(HOUR,@delta,TIMESTAMP)                AS DELTA,&lt;br /&gt;
                  @delta:=TIMESTAMP                                   AS curr_T&lt;br /&gt;
           FROM&lt;br /&gt;
             (SELECT concat(x1.DATE, &amp;quot; &amp;quot;, LPAD(x1.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                     x1.DATE,&lt;br /&gt;
                     x1.HOUR,&lt;br /&gt;
      	              h.READING,&lt;br /&gt;
                     h.VALUE,&lt;br /&gt;
      			      @diff:=0,@delta:=NULL&lt;br /&gt;
              FROM history h&lt;br /&gt;
               INNER JOIN&lt;br /&gt;
                (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                        hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                        max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                        READING&lt;br /&gt;
                 FROM history&lt;br /&gt;
                 WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                   AND READING = &#039;SW_Yield_Daily&#039;&lt;br /&gt;
                   AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                        OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                        AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY)&lt;br /&gt;
           	        )&lt;br /&gt;
                 GROUP BY READING,DATE,HOUR&lt;br /&gt;
                ) x1&lt;br /&gt;
               USING(TIMESTAMP,READING)&lt;br /&gt;
              WHERE    x1.HOUR &amp;gt;= 6&lt;br /&gt;
                   AND x1.HOUR &amp;lt;= 21&lt;br /&gt;
             ) x2&lt;br /&gt;
          ) t1 &lt;br /&gt;
     ) WR&lt;br /&gt;
    right JOIN&lt;br /&gt;
     ( -- Speicher full join from DCto and DCfrom&lt;br /&gt;
      SELECT TIMESTAMP, DCto, DCfrom,&lt;br /&gt;
             cast(&lt;br /&gt;
      		      if((DCfrom IS NULL),&lt;br /&gt;
                      DCto,&lt;br /&gt;
                      if((DCto IS NULL), DCfrom * -1, DCto - DCfrom)&lt;br /&gt;
      			    )*0.85 AS DECIMAL(6)&lt;br /&gt;
                 ) AS yield&lt;br /&gt;
      FROM&lt;br /&gt;
        (SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0, @delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
                    ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21 &lt;br /&gt;
      		      ) x4&lt;br /&gt;
      		   ) t2&lt;br /&gt;
           ) y1 -- DCto&lt;br /&gt;
          LEFT JOIN&lt;br /&gt;
           (-- DCfrom&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
                      VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE, @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP) AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			     ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
                 ) x4&lt;br /&gt;
              ) t2&lt;br /&gt;
          	) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- LEFT JOIN&lt;br /&gt;
         &lt;br /&gt;
       UNION&lt;br /&gt;
         &lt;br /&gt;
         SELECT TIMESTAMP, y1.DCto, y2.DCfrom&lt;br /&gt;
         FROM&lt;br /&gt;
           (-- DCto&lt;br /&gt;
            SELECT TIMESTAMP,&lt;br /&gt;
                   if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCto,&lt;br /&gt;
                   t2.DELTA&lt;br /&gt;
            FROM&lt;br /&gt;
              (SELECT TIMESTAMP,&lt;br /&gt;
                      READING,&lt;br /&gt;
      			    VALUE,&lt;br /&gt;
                      if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                      @diff:=VALUE AS curr_V,&lt;br /&gt;
                      TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                      @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
               FROM&lt;br /&gt;
                 (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                         x3.DATE,&lt;br /&gt;
                         x3.HOUR,&lt;br /&gt;
                         h.READING,&lt;br /&gt;
                         h.VALUE,&lt;br /&gt;
                         @diff:=0,@delta:=NULL&lt;br /&gt;
                  FROM history h&lt;br /&gt;
                   INNER JOIN&lt;br /&gt;
                    (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                            max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                            READING&lt;br /&gt;
                     FROM history&lt;br /&gt;
                     WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                       AND READING = &#039;Battery_Total_DC_ChargeEnergy_DCsideToBattery&#039;&lt;br /&gt;
                       AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                            OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                            AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                     GROUP BY READING,DATE,HOUR&lt;br /&gt;
      			  ) x3&lt;br /&gt;
                   USING(TIMESTAMP,READING)&lt;br /&gt;
                  WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                    AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
      		   ) x4&lt;br /&gt;
      		) t2&lt;br /&gt;
            ) y1 -- DCto&lt;br /&gt;
          RIGHT JOIN&lt;br /&gt;
            (-- DCfrom&lt;br /&gt;
             SELECT TIMESTAMP,&lt;br /&gt;
                    if(t2.DELTA &amp;gt; 6, 0, t2.DIFF) AS DCfrom,&lt;br /&gt;
                    t2.DELTA&lt;br /&gt;
             FROM&lt;br /&gt;
               (SELECT TIMESTAMP,&lt;br /&gt;
                       READING,&lt;br /&gt;
                       VALUE,&lt;br /&gt;
                       if(@diff = 0, 0, cast((VALUE-@diff) AS DECIMAL(10))) AS DIFF,&lt;br /&gt;
                       @diff:=VALUE AS curr_V,&lt;br /&gt;
                       TIMESTAMPDIFF(HOUR, @delta,TIMESTAMP) AS DELTA,&lt;br /&gt;
                       @delta:=TIMESTAMP AS curr_T&lt;br /&gt;
                FROM&lt;br /&gt;
                  (SELECT concat(x3.DATE, &amp;quot; &amp;quot;, LPAD(x3.HOUR, 2, 0), &amp;quot;:00:00&amp;quot;) AS TIMESTAMP,&lt;br /&gt;
                          x3.DATE,&lt;br /&gt;
                          x3.HOUR,&lt;br /&gt;
                          h.READING,&lt;br /&gt;
                          h.VALUE,&lt;br /&gt;
                          @diff:=0,@delta:=NULL&lt;br /&gt;
                   FROM history h&lt;br /&gt;
                    INNER JOIN&lt;br /&gt;
                     (SELECT date(TIMESTAMP) AS DATE,&lt;br /&gt;
                             hour(TIMESTAMP) AS HOUR,&lt;br /&gt;
                             max(TIMESTAMP)  AS TIMESTAMP,&lt;br /&gt;
                             READING&lt;br /&gt;
                      FROM history&lt;br /&gt;
                      WHERE DEVICE = &#039;WR_1&#039;&lt;br /&gt;
                        AND READING = &#039;Battery_Total_DC_DischargeEnergy_DCsideFromBattery&#039;&lt;br /&gt;
                        AND (    TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(365-30) DAY)&lt;br /&gt;
                             OR  TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -(2*365+30) DAY)&lt;br /&gt;
                             AND TIMESTAMP &amp;lt; DATE_ADD(@date,INTERVAL -(2*365-30) DAY))&lt;br /&gt;
                      GROUP BY READING,DATE,HOUR&lt;br /&gt;
        		       ) x3&lt;br /&gt;
                    USING(TIMESTAMP,READING)&lt;br /&gt;
                   WHERE x3.HOUR &amp;gt;= 6&lt;br /&gt;
                     AND x3.HOUR &amp;lt;= 21&lt;br /&gt;
        	        ) x4&lt;br /&gt;
               ) t2&lt;br /&gt;
            ) y2 -- DCfrom&lt;br /&gt;
          USING(TIMESTAMP) -- RIGHT JOIN&lt;br /&gt;
       ) y3&lt;br /&gt;
      &lt;br /&gt;
     ) Speicher -- full join&lt;br /&gt;
     USING(TIMESTAMP)&lt;br /&gt;
   -- end right join&lt;br /&gt;
   &lt;br /&gt;
   -- UNION end&lt;br /&gt;
   &lt;br /&gt;
  ) t12 USING(TIMESTAMP)&lt;br /&gt;
SET tt.yield = t12.yield&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
-- Ermittle Ertrags Maximum der letzten 30 Tage um die Prognose zu limitieren&lt;br /&gt;
UPDATE dwdfull tt&lt;br /&gt;
JOIN&lt;br /&gt;
  ( -- yield_max&lt;br /&gt;
      SELECT hour,&lt;br /&gt;
             cast(max(yield) AS DECIMAL(6)) AS yield_max&lt;br /&gt;
      FROM dwdfull&lt;br /&gt;
      WHERE TIMESTAMP &amp;gt; DATE_ADD(@date,INTERVAL -30 DAY)&lt;br /&gt;
      GROUP BY hour&lt;br /&gt;
   ) t2  USING(hour)&lt;br /&gt;
SET tt.yield_max = t2.yield_max&lt;br /&gt;
WHERE TIMESTAMP &amp;gt; @date&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
IF display = &#039;show&#039; THEN &lt;br /&gt;
  select * from dwdfull LIMIT 3000;&lt;br /&gt;
ELSE&lt;br /&gt;
  select now();&lt;br /&gt;
END IF&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() in einzelnen Schritten====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1. Löschen der bisherigen dwdfull Tabelle&lt;br /&gt;
 2. Anlegen einer neuen dwnfull Tabelle&lt;br /&gt;
 3. Füllen der Tabelle mit den älteren rad1h Werten&lt;br /&gt;
 4. Ergänzen der rad1h Werte für den nächsten Tag&lt;br /&gt;
&lt;br /&gt;
 5. Nun erfolgen alle weiteren DWD Daten in weiteren Spalten der dwdfull Tabelle&lt;br /&gt;
    1. TTT    : Temperature 2m above surface [°C]&lt;br /&gt;
    2. FF     : Windspeed&lt;br /&gt;
    3. Neff   : Effective cloud cover [%]&lt;br /&gt;
    4. R101   : Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]&lt;br /&gt;
    5. R600   : Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]&lt;br /&gt;
    6. RRs1c  : Snow-Rain-Equivalent during the last 3 hours [kg/m2]&lt;br /&gt;
    7. Rad1h  : Global Irradiance [kJ/m2]&lt;br /&gt;
                kJ/m² Umrechnung *0,277778 in kWh/m²&lt;br /&gt;
    8. ww     : Significant Weather&lt;br /&gt;
    9. wwM    : Probability for fog within the last hour [%]&lt;br /&gt;
&lt;br /&gt;
 6. Zum Schluss wird noch der yield der kompletten PV-Anlage ergänzt&lt;br /&gt;
    1. Begonnen wird mit dem AC yield, der stundenweise aus dem Zähler &amp;quot;SW_Yield_Daily&amp;quot; berechnet wird&lt;br /&gt;
       dieser ist jedoch wegen des DC seitigen Speichers nicht korrekt, da in einem Graphen die PV-Leistung&lt;br /&gt;
       erst nach dem entladen zugerechnet wird&lt;br /&gt;
    2. Nun wird der DC yield des Speichers berücksichtigt, was über diese Werte geschieht&lt;br /&gt;
       1. Battery_Total_DC_ChargeEnergy_DCsideToBattery&lt;br /&gt;
       2. Battery_Total_DC_DischargeEnergy_DCsideFromBattery&lt;br /&gt;
    3. Die Ermittlung einer stunden basierten Tabelle ist etwas komplexer und bedarf diverser SELECT mit JOIN (Im MySQL gibt es kein full JOIN)&lt;br /&gt;
&lt;br /&gt;
 7. Der letzte Schritt ist dann die Möglichkeit einer Rückmeldung aus der MySQL Procedure ins FHEM&lt;br /&gt;
 8. Über den Parameter show/none wird der Prozedure die Art der Rückmeldung mitgeteilt&lt;br /&gt;
    1. none wäre der Default und gibt als Ergebnis das aktuelle Datum der Datenbank zurück&lt;br /&gt;
    2. show würde den Inhalt der dwnfull Tabelle an FHEM zurück liefern, was jedoch einige hundert Zeilen sein werden&lt;br /&gt;
&lt;br /&gt;
 9. Die Procedure selectiert nur die entscheidenden Daten für die jeweilige KI Prognose, um das Datenvolumen gering zu halten,&lt;br /&gt;
    denn es macht ja keinen Sinn, die Winter mit den Sommer Daten zu vergleichen&lt;br /&gt;
 &lt;br /&gt;
10. Hierbei werden deshalb folgende Zeiträume jeweils selectiert&lt;br /&gt;
    1. Die letzten 30 Tage ab dem aktuellen Datum&lt;br /&gt;
    2. Vom letzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    3. Vom letzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    4. Vom vorletzten Jahr 30 Tage vor dem Datum&lt;br /&gt;
    5. Vom vorletzten Jahr 30 Tage nach dem Datum&lt;br /&gt;
    6. Die Forecast Daten für den nächsten Tag,&lt;br /&gt;
       an dieser Stelle wäre es natürlich auch denkbar noch weiter in die Zukunft zu gehen,&lt;br /&gt;
       was mir jedoch zu spekulativ ist und nach meiner Meinung bisher für keine Entscheidung von Wichtigkeit wäre.&lt;br /&gt;
 &lt;br /&gt;
11. Die Laufzeit dieser Procedure beträgt auf meinem RPI4 in einem Oracle MySQL Docker Container ca. 50-70 Sekunden,&lt;br /&gt;
    deshalb musste ich bei mir den Timeout der MySQL Workbench für eine Session von 60 Sekunden auf z.B 90 Sekunden erhöhen&lt;br /&gt;
&lt;br /&gt;
12. In einem Interface Eurer Wahl zur Datenbank könnt Ihr die Procedure zum Testen dann aufrufen und das Ergebnis testen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====dwd_load() Test in MySQL aufrufen====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
&lt;br /&gt;
select * from dwdfull&lt;br /&gt;
-- WHERE TIMESTAMP &amp;gt; curdate()&lt;br /&gt;
order by TIMESTAMP desc&lt;br /&gt;
LIMIT 1000;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte nun der Test der Procedure eine gefüllte Tabelle anzeigen, so kann die Integration ins FHEM erfolgen. Hierzu wird dann ein DbRep Device angelegt, dass später zyklisch jede Stunde ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_KI_Prognose (Teil 1)====&lt;br /&gt;
Achtung, bei diesem Device kommt im weiteren Fortschritt noch ein weiteres Attribut zum Aufruf des Python KI Prognose Skriptes hinzu. Im Kommentar wird dies bereits im Syntax erwähnt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_KI_Prognose DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose comment Version 2023.02.23 12:00\&lt;br /&gt;
\&lt;br /&gt;
Hier wird die Vorbereitung für die KI PV-Leistungsprognose durchgeführt\&lt;br /&gt;
\&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);;\&lt;br /&gt;
[none|show] zum Anzeigen des Ergebnisses\&lt;br /&gt;
\&lt;br /&gt;
executeAfterProc:\&lt;br /&gt;
&amp;lt;absoluter Skript Name&amp;gt; &amp;lt;DbLog IP-Adresse&amp;gt; &amp;lt;FHEM IP-Adresse&amp;gt; &amp;lt;DbRep Name&amp;gt; &amp;lt;Wechselricher Name&amp;gt; &amp;lt;Prefix Reading Name&amp;gt;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose executeAfterProc &amp;quot;/opt/fhem/python/bin/PV_KI_Prognose.py 192.168.178.XXX 192.168.178.YYY LogDBRep_PV_KI_Prognose WR_1 Solar_yield_fc&amp;quot;&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose room System&lt;br /&gt;
attr LogDBRep_PV_KI_Prognose verbose 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auch hier sollte nun getestet werden, indem man beim set das sqlCmd ausführt. Der MySQL Procedur Aufruf ist ebenfalls im Kommentar zu finden.&lt;br /&gt;
&lt;br /&gt;
Als Ergebnis sollte soetwas zurück kommen. Nachdem das erschienen ist kann man den obigen Test mit dem SELECT der dwdfull Tabelle nochmals wiederholen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
SqlResultRow_1 NOW()&lt;br /&gt;
SqlResultRow_2 2023-03-17 11:01:03&lt;br /&gt;
sqlCmd call dwd_load(curdate(),&#039;none&#039;);&lt;br /&gt;
sqlResultNumRows 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wetter-/Leistungs-Prognose (nicht mehr aktuell)==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
====Wetter Forecast Grundlagen (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der &lt;br /&gt;
    Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deutscher Wetter Dienst (DWD) (nicht mehr aktuell)===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
====RAW Definition DWD_Forecast (nicht mehr aktuell)====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wurden einige extra Werte vom DWD abgefragt, die für das Solar_Forecast Modul verwendet werden. Dieses Modul ist noch in der experimental Phase (2021.02.23) und liefert noch nicht gleichwertige Ergebnisse. Ein Test zum vergleichen kann aber nicht schaden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast DbLogInclude fc0_.*_Rad1h,fc0_.*_TTT,fc0_.*_Neff,fc0_.*_R101,fc0_.*_RRS1c,fc0_.*_DD,fc0_.*_N,fc0_.*_VV,fc0_.*_SunD1&lt;br /&gt;
attr DWD_Forecast comment Version 2023.01.05 12:40\&lt;br /&gt;
TTT 	: Temperature 2m above surface [°C]\&lt;br /&gt;
Neff	: Effective cloud cover [%]\&lt;br /&gt;
R101	: Probability of precipitation &amp;gt; 0.1 mm during the last hour [%]\&lt;br /&gt;
R600	: Probability of precipitation &amp;gt; 0.0mm during the last 6 hours [%]\&lt;br /&gt;
RRs1c	: Snow-Rain-Equivalent during the last 3 hours [kg/m2]\&lt;br /&gt;
Rad1h	: Global Irradiance [kJ/m2]\&lt;br /&gt;
          kJ/m² Umrechnung *0,277778 in kWh/m²\&lt;br /&gt;
ww	: Significant Weather\&lt;br /&gt;
wwM	: Probability for fog within the last hour [%]&lt;br /&gt;
attr DWD_Forecast event-on-update-reading fc0_.*_[Rad1h|TTT|Neff|R101|RRS1c|DD|N|VV|SunD1].*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600,R101,wwM,ww,RRS1c,DD,N,VV,SunD1&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Leistungsprognose&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 07&lt;br /&gt;
attr DWD_Forecast verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Astro Device===&lt;br /&gt;
====RAW Definition Astro====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====fhem.cfg Einträge für das Astro Device====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===99_myUtils.pm Funktionen===&lt;br /&gt;
====Solar_forecast() (nicht mehr aktuell)====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen, muss ein Dummy WR_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Letzte Neuerungen:&lt;br /&gt;
- IM WR_1_config kann man verbose auf &amp;gt;3 setzen und bekommt dann Log Meldungen&lt;br /&gt;
- Es wird eine Autokorrektur unterstützt. Aktivierung durch &amp;quot;setreading WR_1_config forecast_factor_autocorrection 1&amp;quot;&lt;br /&gt;
  Für die Datenbank Anbindung wird ein DbRep Device LogDBRep_PV_Forecast_SQL verwendet. Die RAW definition kommt gleich im Anschluss.&lt;br /&gt;
- Das SQL für die Berechnung des Faktors der Autokorrektur Verwendet Konfigurationsvariablen aus den DbRep Device.&lt;br /&gt;
- Bei der Autokorrektur wird auch eine Bedeckung von Schnee (Strom im String &amp;lt; 1A) berücksichtigt. (das ist noch in der Entwicklung)&lt;br /&gt;
  Dieser Faktor wird im PV_Schedule Device erzeugt und dann im &amp;quot;WR_1_config module_*_covered&amp;quot; für jeden String eingetragen.&lt;br /&gt;
  Das muss jeder individuell für seine Anlage anpassen!&lt;br /&gt;
- Für die 70% Regelung wird nun auch ein Middayhigh Trigger ermittelt und die jeweilige Start/Stop Zeit. Dies steht dann im WR_1 Device bei den Solar_* readings&lt;br /&gt;
- Es besteht auch die Möglichkeit die Solar_forecast() Funktion ohne Datenbank zu verwenden, dann ist bei den Parametern &amp;quot;none&amp;quot; zu übergeben und&lt;br /&gt;
  es muss auch die Autokorrektur abgeschaltet sein.&lt;br /&gt;
- Anstelle des Wechselrichter Devices kann nun auch ein beliebiges anderes Device angegeben werden, in das dann der Forecast geschrieben wird.&lt;br /&gt;
  Auch hier kann dann keine Autokorrektur verwendet werden.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.06.14 15:20&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;        # Mit dieser Datenbank wird gearbeitet&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zur Kommunikation mit der LogDB verwendet und muss entsprechend konfiguriert sein&lt;br /&gt;
     my $logdevice   = &amp;quot; &amp;quot;   ;        # Das ist der Wechselrichter, oder ein anderes Device, in das die Prognose geschrieben wird&lt;br /&gt;
        $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;    # Der reading Name wird um 0 oder 1 verlängert&lt;br /&gt;
&lt;br /&gt;
     # Welcher Verbose Level ist gesetzt?&lt;br /&gt;
     my $verbose = AttrVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Gibt es einen festen Korrekturfaktor für jede Stunde?&lt;br /&gt;
     my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
     # Soll eine Autokorrektur gemacht werden? 0 = Nein 1 = Ja&lt;br /&gt;
     my $autocorrection          = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor_autocorrection&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Beim DWD wird der Wert für die Stunde erst am Ende der Stunde eingetragen&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     # Hier werden die Variablen vorbelegt&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry1h,$logentry4h,$logentryrest,$logentry,$i) = (0) x 9 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($module_covered,$Solar_Correction_Faktor_auto,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 6 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 06:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $logdbrep ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
       # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
       CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Setzen der Tageszähler und Merker&lt;br /&gt;
     $logentry            = 0 ;   # Summiert den Solar_Calculation Wert für den ganzen Tag&lt;br /&gt;
     $logentry4h          = 0 ;   # Summierung für die nächsten vier Stunden&lt;br /&gt;
     $logentryrest        = 0 ;   # Summierung für den Rest des Tages&lt;br /&gt;
&lt;br /&gt;
     my $middayhigh           = 0 ; # Ein Merker, ob das Tagesmaximum überschritten wird&lt;br /&gt;
     my $middayhigh_start     = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_stop      = &amp;quot;00:00&amp;quot;;&lt;br /&gt;
     my $middayhigh_tmp       = 0;&lt;br /&gt;
     my $middayhigh_start_tmp = 0;&lt;br /&gt;
     my $middayhigh_stop_tmp  = 0;&lt;br /&gt;
&lt;br /&gt;
     my $Inverter_Max_Power = ReadingsVal($logdevice.&amp;quot;_Speicher_1_ExternControl&amp;quot;,&amp;quot;SpeicherMidday_Inverter_Max_Power&amp;quot;,&amp;quot;unused&amp;quot;);  # Überschreiben des middayhigh&lt;br /&gt;
     if ($Inverter_Max_Power eq &amp;quot;unused&amp;quot;) {&lt;br /&gt;
       $Inverter_Max_Power = ReadingsVal($logdevice,&amp;quot;Inverter_Max_Power&amp;quot;,0) +500 ;      # Hier wird ein Durchschnittsverbrauch des Hauses aufaddiert&lt;br /&gt;
     } else {&lt;br /&gt;
       if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power manuell gesetzt&amp;quot; } ;&lt;br /&gt;
     };&lt;br /&gt;
     if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;SpeicherMidday_Inverter_Max_Power auf &amp;quot;.$Inverter_Max_Power.&amp;quot; gesetzt&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
     # Es werden Stundenwerte von 06:00 bis 21:00 Uhr berechnet&lt;br /&gt;
     for ($i = 6; $i &amp;lt;= 21; $i++) {&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0 and $i == 6) {&lt;br /&gt;
         # Neuberechnung der stündlichen Autokorrektur Faktoren in der Datenbank. Das DbRep Device LogDBRep_PV_Forecast_SQL muss vorhanden sein.&lt;br /&gt;
         # Achtung, beim SQL muss &#039;@&#039; mit &#039;\@&#039; maskiert werden.&lt;br /&gt;
         CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking &amp;quot;.sprintf(&amp;quot;&lt;br /&gt;
               INSERT INTO history&lt;br /&gt;
                 (TIMESTAMP,DEVICE,READING,VALUE)&lt;br /&gt;
                  SELECT&lt;br /&gt;
                    TIMESTAMP,DEVICE,READING,VALUE&lt;br /&gt;
                  FROM (&lt;br /&gt;
                    SELECT&lt;br /&gt;
                      DATE_ADD(CURDATE(),INTERVAL t2.HOUR HOUR) AS TIMESTAMP,&lt;br /&gt;
                      t2.DEVICE,&lt;br /&gt;
                      \@readingname                             AS READING,&lt;br /&gt;
                      cast(if(avg(t2.FACTOR) &amp;gt; 1.6, 1.6,&lt;br /&gt;
                              avg(t2.FACTOR) ) AS DECIMAL(2,1)) AS VALUE&lt;br /&gt;
                    FROM (&lt;br /&gt;
                      SELECT * FROM (&lt;br /&gt;
                        SELECT&lt;br /&gt;
                          t1.TIMESTAMP,&lt;br /&gt;
                          t1.HOUR,&lt;br /&gt;
                          t1.DEVICE,&lt;br /&gt;
                          t1.READING,&lt;br /&gt;
                          t1.VALUE,&lt;br /&gt;
                          if(\@diff = 0,0, \@temp:=cast((t1.VALUE-\@diff) AS DECIMAL(8,2)))                                    AS DIFF,&lt;br /&gt;
                          if(((t1.VALUE+(-1*\@temp))*\@corr)=0,0, cast((t1.VALUE/(t1.VALUE+(-1*\@temp))*\@corr) AS DECIMAL(8,1))) AS FACTOR,&lt;br /&gt;
                          \@diff:=t1.VALUE                                                                                        AS curr_V&lt;br /&gt;
                        FROM (&lt;br /&gt;
                          SELECT&lt;br /&gt;
                            h.TIMESTAMP,&lt;br /&gt;
                            date(h.TIMESTAMP) AS DATE,&lt;br /&gt;
                            hour(h.TIMESTAMP) AS HOUR,&lt;br /&gt;
                            h.DEVICE,&lt;br /&gt;
                            h.READING,&lt;br /&gt;
                            h.VALUE&lt;br /&gt;
                          FROM history AS h&lt;br /&gt;
                          WHERE h.DEVICE    =  \@device&lt;br /&gt;
                            AND (h.READING  =  \@reading1 OR h.READING = \@reading2)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;gt;= DATE_SUB(DATE(now()),INTERVAL \@days DAY)&lt;br /&gt;
                            AND h.TIMESTAMP &amp;lt;= CURDATE()&lt;br /&gt;
                            AND MINUTE(h.TIMESTAMP) = 0&lt;br /&gt;
                            AND h.VALUE &amp;gt;= 50&lt;br /&gt;
                          GROUP BY DATE,HOUR,h.READING,h.DEVICE,h.TIMESTAMP&lt;br /&gt;
                         )t1&lt;br /&gt;
                       )tx&lt;br /&gt;
                        WHERE READING != \@reading2&lt;br /&gt;
                          AND HOUR &amp;gt; 6&lt;br /&gt;
                     )t2&lt;br /&gt;
                      GROUP BY t2.HOUR,t2.DEVICE&lt;br /&gt;
                   )t3&lt;br /&gt;
                    WHERE&lt;br /&gt;
                      t3.VALUE != 0&lt;br /&gt;
                    ORDER BY TIMESTAMP&lt;br /&gt;
                    ON DUPLICATE KEY UPDATE&lt;br /&gt;
                      VALUE=t3.VALUE;&lt;br /&gt;
           &amp;quot;) # Ende sprintf()&lt;br /&gt;
         );   # Ende CommandGet()&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
       $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
       $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
       if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
         $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
&lt;br /&gt;
         $Solar_Rain = 0;&lt;br /&gt;
         for (my $r600 = $i+5; $r600 &amp;gt;= $i; $r600--) {&lt;br /&gt;
           $Solar_Rain        += ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($r600+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
         $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
         $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
         $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
         if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation.&amp;quot; W &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0).&amp;quot; J&amp;quot; } ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($cloudk ne 0) {&lt;br /&gt;
         $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
         $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($raink ne 0) {&lt;br /&gt;
         $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
       if ($tempk ne 0) {&lt;br /&gt;
         $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
         $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       if ($autocorrection ne 0) {&lt;br /&gt;
         $Solar_Correction_Faktor_auto = CommandGet(undef, $logdbrep.&amp;quot; sqlCmdBlocking SELECT VALUE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;Solar_Correction_Faktor_auto&#039; AND TIMESTAMP=&#039;&amp;quot;.sprintf(&amp;quot;%4d-%02d-%02d %02d:00:00&amp;quot;,$year,$mon,$mday,$i).&amp;quot;&#039;;&amp;quot;) ;&lt;br /&gt;
         if($Solar_Correction_Faktor_auto eq &amp;quot;&amp;quot;) { $Solar_Correction_Faktor_auto = 1; };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       $logentry1h = 0 ;   # Summierung für eine Stunde zurücksetzen&lt;br /&gt;
&lt;br /&gt;
       # Es werden 5 Modul Ausrichtungen durchlaufen, der Name der Ausrichtung befindet sich z.B. in WR_1_config&lt;br /&gt;
       for(my $j=1;$j&amp;lt;=5;$j++){&lt;br /&gt;
         # lesen der Modul Anzahl&lt;br /&gt;
         $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
         if ($module_count[$j] ne 0) {&lt;br /&gt;
           # Für diese Ausrichtung sind Module Installiert&lt;br /&gt;
&lt;br /&gt;
           # Berechnung des Korrekturfaktors für die Modul Ausrichtung&lt;br /&gt;
           $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;factor/plain/direction       : &amp;quot;.$Solar_Plain.&amp;quot; &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) };&lt;br /&gt;
           # Berechnung der Modul Nennleistung für diese Ausrichtung&lt;br /&gt;
           $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
           # Anwendung der Korrekturfaktoren&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp   * $Solar_Correction_Cloud * $Solar_Correction_Rain ;&lt;br /&gt;
           $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Faktor ;&lt;br /&gt;
&lt;br /&gt;
           if ($autocorrection ne 0) {&lt;br /&gt;
             # Nachsehen, ob dieser String mit Schnee bedeckt ist&lt;br /&gt;
             $module_covered = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_covered&amp;quot;,1) ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $Solar_Correction_Faktor_auto ;&lt;br /&gt;
             $Solar_[$j]     = $Solar_[$j] * $module_covered ;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot;_covered             : &amp;quot;.$module_covered };&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Runden auf volle Watt Werte&lt;br /&gt;
           $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
           if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;module_&amp;quot;.$j.&amp;quot; estimation          : &amp;quot;.$Solar_[$j] };&lt;br /&gt;
&lt;br /&gt;
           # Aufsummieren aller konfigurierter Ausrichtungen&lt;br /&gt;
           $logentry1h += $Solar_[$j] ; # Summe für eine Stunde (wird mit jedem lauf von $i wieder auf 0 gesetzt)&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe der nächsten 4 h gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour and $i &amp;lt;= $hour+3) {&lt;br /&gt;
             $logentry4h += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           # Hier wird die Summe für den Resttag gebildet&lt;br /&gt;
           if ($fc == 0 and $i &amp;gt;= $hour) {&lt;br /&gt;
             $logentryrest += $Solar_[$j] ;&lt;br /&gt;
           };&lt;br /&gt;
&lt;br /&gt;
           $logentry += $Solar_[$j] ; # Summe für den ganzen Tag&lt;br /&gt;
&lt;br /&gt;
           # Den Forecast Wert für die aktuelle Stunde in das Wechselrichter Device schreiben&lt;br /&gt;
           if ($fc == 0 and $hour == $i) {&lt;br /&gt;
             if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;                   : &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; };&lt;br /&gt;
             CommandSetReading(undef, $logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j]) ;&lt;br /&gt;
           };&lt;br /&gt;
         };&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Alle Forecast Werte für die jeweilige Stunde in die DbLog schreiben (Es wird der Cache verwendet)&lt;br /&gt;
&lt;br /&gt;
       if ( $logdb ne &amp;quot;none&amp;quot; ) {&lt;br /&gt;
         CommandSet(undef, $logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry1h.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry1h.&amp;quot;|&amp;quot;) ;&lt;br /&gt;
&lt;br /&gt;
         if ( $middayhigh == 0 and $logentry1h &amp;gt; $Inverter_Max_Power ) {&lt;br /&gt;
           $middayhigh           = 1;&lt;br /&gt;
           $middayhigh_start_tmp = $i-1;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;lt; $Inverter_Max_Power and $middayhigh_stop_tmp == 0 )  {&lt;br /&gt;
           $middayhigh_stop_tmp = $i;&lt;br /&gt;
         };&lt;br /&gt;
         if ( $middayhigh == 1 and $logentry1h &amp;gt; $Inverter_Max_Power and $middayhigh_stop ne &amp;quot;00:00&amp;quot; )  {&lt;br /&gt;
           $middayhigh_stop_tmp = 0;                                # da war ein kurzer Einbruch, es sollte noch länger sein.&lt;br /&gt;
         };&lt;br /&gt;
         if ($middayhigh == 1 and&lt;br /&gt;
             $middayhigh_stop_tmp != 0 and&lt;br /&gt;
             $middayhigh_stop_tmp == $i ) {                                    # das Ende des Middayhigh wurde gefunden&lt;br /&gt;
&lt;br /&gt;
           $middayhigh_tmp = $middayhigh_stop_tmp - $middayhigh_start_tmp;&lt;br /&gt;
           if ( $middayhigh_tmp &amp;gt; 4 )  {                                       # das Middayhigh wird zu lang&lt;br /&gt;
             if ($verbose &amp;gt;= 3 ) {                                             # die bisherigen Zeiten ausgeben&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp) ;&lt;br /&gt;
             }&lt;br /&gt;
             $middayhigh_tmp       = round(($middayhigh_tmp/4)-0.2 ,0);        # die Rundung der Zeit zum Abziehen etwas verschieben&lt;br /&gt;
             $middayhigh_start_tmp = $middayhigh_start_tmp + $middayhigh_tmp;  # es wird um ganze Stunden verkürzt&lt;br /&gt;
             $middayhigh_stop_tmp  = $middayhigh_stop_tmp  - $middayhigh_tmp;&lt;br /&gt;
             if ($verbose &amp;gt;= 3) {                                              # melde die Verkürzung&lt;br /&gt;
               Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;         : verkürzt um &amp;quot;.($middayhigh_tmp *2).&amp;quot; Stunden&amp;quot;;&lt;br /&gt;
             }&lt;br /&gt;
           };&lt;br /&gt;
           $middayhigh_start = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_start_tmp);&lt;br /&gt;
           $middayhigh_stop  = sprintf(&amp;quot;%02d:00&amp;quot;,$middayhigh_stop_tmp);&lt;br /&gt;
           if ($verbose &amp;gt;= 3) {                                                # gib die finalen Zeiten aus&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start   : &amp;quot;.$middayhigh_start;&lt;br /&gt;
             Log 3, &amp;quot;Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop    : &amp;quot;.$middayhigh_stop ;&lt;br /&gt;
           }&lt;br /&gt;
         };&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ; # setz die Zeiten im Device&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Sobald mindestens ein String configuriert ist sollen diese Werte, der aktuellen Stunde, in das Wechselrichter Device geschrieben werden&lt;br /&gt;
       if ($fc == 0 and $hour == $i and $module_count[1] ne 0) {&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp) ;&lt;br /&gt;
         CommandSetReading(undef, $logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry1h) ;&lt;br /&gt;
       };&lt;br /&gt;
&lt;br /&gt;
       # Auch die Solar_Calculation jeder einzelnen Stunde wird als reading in das Wechselrichter Device geschrieben&lt;br /&gt;
       CommandSetReading(undef, sprintf(&amp;quot;%s %s_%02d %d&amp;quot;,$logdevice,$reading,$i,$logentry1h)) ;&lt;br /&gt;
&lt;br /&gt;
       # Für die Fehlersuche kommen noch einige Informationen ins Log&lt;br /&gt;
       if ($verbose &amp;gt;= 3) {&lt;br /&gt;
         Log 3, &amp;quot;Solar_SolarRadiation         : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Cloud                  : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;cloudk                       : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Cloud       : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Rain                   : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;raink                        : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Rain        : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Temp                   : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;tempk                        : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Temp        : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor      : &amp;quot;.$Solar_Correction_Faktor ;&lt;br /&gt;
         Log 3, &amp;quot;Solar_Correction_Faktor_auto : &amp;quot;.$Solar_Correction_Faktor_auto ;&lt;br /&gt;
         Log 3, &amp;quot;Forecast,Hour,Estimation 1h  : &amp;quot;.$fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$logentry1h ;&lt;br /&gt;
       };&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     # Die Summe der nächsten 4 Stunden in das Wechselrichter Device schreiben&lt;br /&gt;
     if ($fc == 0) {&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_4h &amp;quot;.$logentry4h) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_rest &amp;quot;.$logentryrest) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
     CommandSetReading(undef, $logdevice.&amp;quot; &amp;quot;.$reading.&amp;quot;_day &amp;quot;.$logentry) ;&lt;br /&gt;
&lt;br /&gt;
     if ( $middayhigh == 0 ) {    # Auf Defaults zurücksetzen&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot; &amp;quot;.$middayhigh) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_start &amp;quot;.$middayhigh_start) ;&lt;br /&gt;
       CommandSetReading(undef, $logdevice.&amp;quot; Solar_middayhigh_fc&amp;quot;.$fc.&amp;quot;_stop &amp;quot;.$middayhigh_stop) ;&lt;br /&gt;
     };&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() (nicht mehr aktuell)====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2021.02.28 17:00&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    my $verbose     = AttrVal(&amp;quot;Astro&amp;quot;,&amp;quot;verbose&amp;quot;,0) ;&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = CommandGet(undef, &amp;quot;Astro text SunAz &amp;quot;.$time) ;&lt;br /&gt;
    my $elevation   = CommandGet(undef, &amp;quot;Astro text SunAlt &amp;quot;.$time) ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain time             : &amp;quot;.$time;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain azimuth          : &amp;quot;.$azimuth;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain elevation        : &amp;quot;.$elevation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain orientation      : &amp;quot;.$orientation;&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain angle            : &amp;quot;.$angle;&lt;br /&gt;
    };&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.1798) {&lt;br /&gt;
      if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    if ($verbose &amp;gt;= 3) { Log 3, &amp;quot;Solar_plain factor           : &amp;quot;.$factor };&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===DbLog/DbRep Device===&lt;br /&gt;
====RAW Definition LogDB====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====RAW Definition LogDBRep_PV_Forecast_SQL (nicht mehr aktuell)====&lt;br /&gt;
Dieses Device war vormals das LogDBRep_PV_Forecast_SQL , es wird jedoch nun mehrfach verwendet und wurde deshalb umbenannt. Das LogDBRep_PV_Forecast_SQL kann gelöscht werden.&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
Für die Solar_forecast() Funktion wurden hier SQL Variablen Definiert, die für die Autokorrektur verwendet werden:&lt;br /&gt;
- @days ist die Anzahl der Tage, über die ein stündlicher, durchschnitts Korrektur Faktor berechnet wird.&lt;br /&gt;
- @corr ermöglicht es diesen Faktor nochmals zu verändern &amp;lt;1 dämpft, &amp;gt;1 verstärkt&lt;br /&gt;
- @device ist der Plenticore Wechselrichter&lt;br /&gt;
- @reading1 ist die reale DC Leistung ohne die Batterie, hier wird &#039;&#039;&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;&#039;&#039; für die Schwarm Implementierung verwendet.&lt;br /&gt;
- @reading2 wird der Basisname der readings im WR_1 Device&lt;br /&gt;
- @readingname wird der reading Name des Korrekturfaktors.&lt;br /&gt;
Bitte beachtet, dass die Namen auch in anderen Devices eingetragen sind, wenn Ihr diese verändern wollt.&lt;br /&gt;
Durch die Erweiterung zum Schwarm mit mehreren AC-Quellen wurde die Variable @reading1 verändert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_Forecast_SQL DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL allowDeletion 1&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL room System&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdHistoryLength 5&lt;br /&gt;
attr LogDBRep_PV_Forecast_SQL sqlCmdVars SET @days:=3, @corr:=0.7, @diff:=0, @temp:=0, @device:=&#039;WR_1&#039;, @reading1:=&#039;SW_Total_DC_P_sumOfAllPVInputs&#039;, @reading2:=&#039;Solar_Calculation_fc0&#039;, @readingname:=&#039;Solar_Correction_Faktor_auto&#039; ;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solar Forcast Tests (nicht mehr aktuell)===&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
&lt;br /&gt;
2.) DbLog / DbRep&lt;br /&gt;
2.1) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
2.2) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
&lt;br /&gt;
3.) Es kann auch ohne DbLog / DbRep gearbeitet werden&lt;br /&gt;
&lt;br /&gt;
4.) Die Solar_* Funktionen in der 99_myUtils&lt;br /&gt;
&lt;br /&gt;
5.) Das DWD Device nit dem Namen DWD_Forecast&lt;br /&gt;
6.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Astro Device Test====&lt;br /&gt;
Bei diesem Test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_plain() Test (nicht mehr aktuell)====&lt;br /&gt;
Diese Funktion kann man folgendermaßen testen. Für Log Meldungen muss man im &#039;&#039;&#039;Astro Device verbose auf 3&#039;&#039;&#039; oder größer stellen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung, das Dach hätte demnach also Süd/West Lage.&lt;br /&gt;
&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann Folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:51:27.312 3: Solar_plain azimuth          : 210.6&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain elevation        : 0.49916224518291&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain orientation      : 0.185004188774085&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain angle            : 0.785395141022061&lt;br /&gt;
2021.04.07 15:51:27.313 3: Solar_plain factor           : 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurückgeliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2021-03-03 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Solar_forecast() Test (nicht mehr aktuell)====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
Bei gesetztem &amp;quot;&#039;&#039;&#039;attr Astro verbose 3&#039;&#039;&#039;&amp;quot; erscheinen hier ebenfalls die Astro Log Informationen.&lt;br /&gt;
Durch setzen von &amp;quot;&#039;&#039;&#039;attr WR_1_config verbose 3&#039;&#039;&#039;&amp;quot; bekommt man die Log Meldungen vom Sorar_forecast()&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_PV_Forecast_SQL&amp;quot;,&amp;quot;WR_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&lt;br /&gt;
generische Verwendung ohne DbLog/DbRep: &#039;&#039;&#039;Das Astro Device muss &amp;quot;Astro&amp;quot; heißen und das DWD Device muss &amp;quot;DWD_Forecast&amp;quot; heißen!!&#039;&#039;&#039;&lt;br /&gt;
{Solar_forecast(&amp;quot;none&amp;quot;,&amp;quot;none&amp;quot;,&amp;quot;&amp;lt;beliebiges Device&amp;gt;&amp;quot;,&amp;quot;&amp;lt;prefix für die readings&amp;gt;_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,[0|1])}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann solche Blöcke, die man zusammenhängend betrachten sollte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power manuell gesetzt&lt;br /&gt;
2021.04.07 15:57:23.866 3: SpeicherMidday_Inverter_Max_Power auf 7000 gesetzt&lt;br /&gt;
2021.04.07 15:57:23.932 3: Solar_SolarRadiation         : 17 W 60.00 J        &amp;lt;&amp;lt;&amp;lt; vom DWD gelieferte Prognose in Watt und Joul&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain azimuth          : 80.2                &amp;lt;&amp;lt;&amp;lt; Astro Informationen&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.976 3: Solar_plain orientation      : -0.171041608489249&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.977 3: Solar_plain factor           : 0.001               &amp;lt;&amp;lt;&amp;lt; Die Funktion ist noch außerhalb des Gültigkeitsbereiches&lt;br /&gt;
2021.04.07 15:57:23.977 3: factor/plain/direction       : 0.001 40/-90     &lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1_covered             : 1                   &amp;lt;&amp;lt;&amp;lt; Ein Faktor für die Schneebedeckung&lt;br /&gt;
2021.04.07 15:57:23.978 3: module_1 estimation          : 0                   &amp;lt;&amp;lt;&amp;lt; Die erwartete Leistung liegt bei 0 Watt&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:23.991 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:23.991 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2_covered             : 1&lt;br /&gt;
2021.04.07 15:57:23.992 3: module_2 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.001 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain orientation      : -1.94183189053337&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.002 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.002 3: factor/plain/direction       : 0.001 40/0&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.002 3: module_3 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain azimuth          : 80.2&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain elevation        : 0.0226891929628595&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain orientation      : -3.31262217257749&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain angle            : 0.698129014241832&lt;br /&gt;
2021.04.07 15:57:24.013 3: Solar_plain factor           : 0.001&lt;br /&gt;
2021.04.07 15:57:24.013 3: factor/plain/direction       : 0.001 40/90&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4_covered             : 1&lt;br /&gt;
2021.04.07 15:57:24.013 3: module_4 estimation          : 0&lt;br /&gt;
2021.04.07 15:57:24.020 3: Solar_SolarRadiation         : 17                  &amp;lt;&amp;lt;&amp;lt; Rad1h ist 70 Watt&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Cloud                  : 70                  &amp;lt;&amp;lt;&amp;lt; 70 % Abdeckung des Himmels durch Wolken&lt;br /&gt;
2021.04.07 15:57:24.021 3: cloudk                       : -0.45 0             &amp;lt;&amp;lt;&amp;lt; Werte der Korrekturfunktion für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.021 3: Solar_Correction_Cloud       : 0.685               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Bewölkung&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Rain                   : 152&lt;br /&gt;
2021.04.07 15:57:24.022 3: raink                        : -0.2 0&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Correction_Rain        : 0.696               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für Regen&lt;br /&gt;
2021.04.07 15:57:24.022 3: Solar_Temp                   : 10.7                &amp;lt;&amp;lt;&amp;lt; Erwartete Temperatur an den Modulen (Schätzung) &lt;br /&gt;
2021.04.07 15:57:24.023 3: tempk                        : -0.39 25&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Temp        : 1.056               &amp;lt;&amp;lt;&amp;lt; Errechneter Korrekturfaktor für die Modultemperatur&lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor      : 1                   &amp;lt;&amp;lt;&amp;lt; Fester Korrekturfaktor aus WR_1_config &lt;br /&gt;
2021.04.07 15:57:24.023 3: Solar_Correction_Faktor_auto : 0.5                 &amp;lt;&amp;lt;&amp;lt; Korrekturfaktor aus der Datenbank Berechnung der letzten Tage &lt;br /&gt;
2021.04.07 15:57:24.024 3: Forecast,Hour,Estimation 1h  : 0 7 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Forecast Basiseinstellung (nicht mehr aktuell)===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät WR_1_config von einer Ost/Süd/West Anlage mitgeliefert (setstate). Es werden bis zu 5 Strings unterstützt.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auch &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät WR_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch zusätzliche Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Berücksichtigung von Temperatur, Bewölkung und Regen (nicht mehr aktuell)===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das Ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
Durch die Autokorrektur ist nun auch ein Schnee Faktor dazu gekommen. Dieser wird im PV_Schedule Device &amp;quot;berechnet&amp;quot; :-) und und in das PV_1_config geschrieben. Bei aktivierter Autokorrektur wird dieser dann berücksichtigt.&lt;br /&gt;
=====Temperatur (nicht mehr aktuell)=====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Wolken und Regen (nicht mehr aktuell)=====&lt;br /&gt;
Aus den DWD_Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken Einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
===wunderground===&lt;br /&gt;
Dieser Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das kann dann als aktueller Wert in den Diagrammen angezeigt werden und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mit einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
&lt;br /&gt;
===RAW Definition Wetter_&amp;lt;Wohnort&amp;gt;===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit Grafana==&lt;br /&gt;
Grafana kann z.B. mit docker auf dem selben oder auch einem anderen System installiert werden. Es ermöglicht die Darstellung von Diagrammen und Dashboards durch die direkte Abfrage aus einer Datenbank.&lt;br /&gt;
===Beispiel Diagramme===&lt;br /&gt;
[[Datei:Leistung und Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
[[Datei:Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Die verwendete Datenbank ist im Grafana als &amp;quot;FHEM MySQL&amp;quot; am besten vorher zu konfigurieren.&lt;br /&gt;
Achtung, dieses Dashboard verwendet die Schwarm readings bei den MySQL SELECT!&lt;br /&gt;
Eine Anpassung wäre denkbar, wenn man im JSON File &amp;quot;SW_&amp;quot; global entfernt.&lt;br /&gt;
Auch die Hauptverbraucher sind im Diagramm anzupassen, da sie bei mir durch eigene Zähler erfasst werden. Sollten bei Euch keine Zähler vorhanden sein, so müsstet Ihr den jeweiligen Verbraucher im Diagramm löschen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;JSON&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;builtIn&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;datasource&amp;quot;: &amp;quot;-- Grafana --&amp;quot;,&lt;br /&gt;
        &amp;quot;enable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;iconColor&amp;quot;: &amp;quot;rgba(0, 211, 255, 1)&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Annotations &amp;amp; Alerts&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;dashboard&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;editable&amp;quot;: true,&lt;br /&gt;
  &amp;quot;gnetId&amp;quot;: null,&lt;br /&gt;
  &amp;quot;graphTooltip&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;id&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;links&amp;quot;: [],&lt;br /&gt;
  &amp;quot;panels&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Actual_Battery_charge_usable_P value&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_Battery value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_PV value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;: &amp;quot;rgb(90, 90, 90)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Home_own_consumption_from_grid value&amp;quot;: &amp;quot;rgb(250, 250, 250)&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_AC_Active_P&amp;quot;: &amp;quot;dark-orange&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P&amp;quot;: &amp;quot;semi-dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 0&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: false,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:78&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:79&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:80&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 10,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:81&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:82&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;$$hashKey&amp;quot;: &amp;quot;object:83&amp;quot;,&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 5,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;hide&amp;quot;: true,&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS &#039;SW_Total_DC_P&#039;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_grid\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_grid&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_grid&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_PV\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_PV&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_PV&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Home_own_consumption_from_Battery\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Home_own_consumption_from_Battery&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Home_own_consumption_from_Battery&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Actual_Battery_charge_usable_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Actual_Battery_charge_usable_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Actual_Battery_charge_usable_P&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  VALUE AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_AC_Active_P\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_AC_Active_P&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;A&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Leistungsbezug&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;Heizung&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Heizung value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Pool&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Shaun value&amp;quot;: &amp;quot;dark-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Waschmaschine&amp;quot;: &amp;quot;light-red&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 12,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 12&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 3,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;hideEmpty&amp;quot;: false,&lt;br /&gt;
        &amp;quot;hideZero&amp;quot;: false,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: &amp;quot;current&amp;quot;,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: true,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;connected&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 0&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;stack&amp;quot;: true,&lt;br /&gt;
          &amp;quot;steppedLine&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_Max\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_Max&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;SW_Total_DC_P_Max&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SW_Total_DC_P_Max&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  abs(avg(value)) AS \&amp;quot;Heizung\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;StromZaehler_Heizung&#039; AND\n  READING = &#039;SMAEM1901401955_Saldo_Wirkleistung&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Heizung&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;StromZaehler_Heizung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;SMAEM1901401955_Saldo_Wirkleistung&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Pool\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly02&#039; AND\n  READING = &#039;Power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Pool&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly02&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Waschmaschine\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly03&#039; AND\n  READING = &#039;power&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Waschmaschine&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly03&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Brunnen\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_0&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Brunnen&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Shaun\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;shelly05&#039; AND\n  READING = &#039;power_1&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Shaun&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;shelly05&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;power_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hauptverbraucher&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;14000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;aliasColors&amp;quot;: {&lt;br /&gt;
        &amp;quot;SW_Total_DC_P_Max value&amp;quot;: &amp;quot;dark-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation&amp;quot;: &amp;quot;dark-yellow&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0&amp;quot;: &amp;quot;super-light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc0 value&amp;quot;: &amp;quot;light-green&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_Calculation_fc1 value&amp;quot;: &amp;quot;dark-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_East value&amp;quot;: &amp;quot;super-light-blue&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_South value&amp;quot;: &amp;quot;light-red&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West&amp;quot;: &amp;quot;light-purple&amp;quot;,&lt;br /&gt;
        &amp;quot;Solar_West value&amp;quot;: &amp;quot;super-light-purple&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;bars&amp;quot;: false,&lt;br /&gt;
      &amp;quot;dashLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;dashes&amp;quot;: false,&lt;br /&gt;
      &amp;quot;datasource&amp;quot;: null,&lt;br /&gt;
      &amp;quot;decimals&amp;quot;: null,&lt;br /&gt;
      &amp;quot;fieldConfig&amp;quot;: {&lt;br /&gt;
        &amp;quot;defaults&amp;quot;: {&lt;br /&gt;
          &amp;quot;links&amp;quot;: []&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;overrides&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;fill&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;fillGradient&amp;quot;: 0,&lt;br /&gt;
      &amp;quot;gridPos&amp;quot;: {&lt;br /&gt;
        &amp;quot;h&amp;quot;: 13,&lt;br /&gt;
        &amp;quot;w&amp;quot;: 23,&lt;br /&gt;
        &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;y&amp;quot;: 24&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;hiddenSeries&amp;quot;: false,&lt;br /&gt;
      &amp;quot;id&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;legend&amp;quot;: {&lt;br /&gt;
        &amp;quot;alignAsTable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;avg&amp;quot;: false,&lt;br /&gt;
        &amp;quot;current&amp;quot;: true,&lt;br /&gt;
        &amp;quot;max&amp;quot;: false,&lt;br /&gt;
        &amp;quot;min&amp;quot;: false,&lt;br /&gt;
        &amp;quot;rightSide&amp;quot;: true,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sideWidth&amp;quot;: 250,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sortDesc&amp;quot;: null,&lt;br /&gt;
        &amp;quot;total&amp;quot;: false,&lt;br /&gt;
        &amp;quot;values&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;lines&amp;quot;: true,&lt;br /&gt;
      &amp;quot;linewidth&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;nullPointMode&amp;quot;: &amp;quot;null&amp;quot;,&lt;br /&gt;
      &amp;quot;options&amp;quot;: {&lt;br /&gt;
        &amp;quot;alertThreshold&amp;quot;: true&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;percentage&amp;quot;: false,&lt;br /&gt;
      &amp;quot;pluginVersion&amp;quot;: &amp;quot;7.5.5&amp;quot;,&lt;br /&gt;
      &amp;quot;pointradius&amp;quot;: 2,&lt;br /&gt;
      &amp;quot;points&amp;quot;: false,&lt;br /&gt;
      &amp;quot;renderer&amp;quot;: &amp;quot;flot&amp;quot;,&lt;br /&gt;
      &amp;quot;seriesOverrides&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;linewidth&amp;quot;: 2&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;alias&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;fill&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;spaceLength&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;stack&amp;quot;: false,&lt;br /&gt;
      &amp;quot;steppedLine&amp;quot;: false,&lt;br /&gt;
      &amp;quot;targets&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc0\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc0&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc0&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc0&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  TIMESTAMP AS \&amp;quot;time\&amp;quot;,\n  value AS \&amp;quot;Solar_Calculation_fc1\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation_fc1&#039;\nORDER BY TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation_fc1&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation_fc1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;SW_Total_DC_P_sumOfAllPVInputs\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;SW_Total_DC_P_sumOfAllPVInputs&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Power_DC_Sum&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Power_DC_Sum&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;Solar_Calculation\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_Calculation&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;Solar_Calculation&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;Solar_Calculation&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_Ost\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_Ost&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_Ost&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_Ost&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_1_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_1_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_1_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_Sued\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_Sued&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_Sued&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_Sued&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;datasource&amp;quot;: &amp;quot;FHEM MySQL&amp;quot;,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;table&amp;quot;,&lt;br /&gt;
          &amp;quot;group&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;$__interval&amp;quot;,&lt;br /&gt;
                &amp;quot;previous&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;metricColumn&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
          &amp;quot;rawQuery&amp;quot;: true,&lt;br /&gt;
          &amp;quot;rawSql&amp;quot;: &amp;quot;SELECT\n  $__timeGroupAlias(TIMESTAMP,$__interval,previous),\n  avg(value) AS \&amp;quot;WR_2_West\&amp;quot;\nFROM history\nWHERE\n  $__timeFilter(TIMESTAMP) AND\n  DEVICE = &#039;WR_1&#039; AND\n  READING = &#039;Solar_WR_2_West&#039;\nGROUP BY 1\nORDER BY $__timeGroup(TIMESTAMP,$__interval,previous)&amp;quot;,&lt;br /&gt;
          &amp;quot;refId&amp;quot;: &amp;quot;WR_2_West&amp;quot;,&lt;br /&gt;
          &amp;quot;select&amp;quot;: [&lt;br /&gt;
            [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;column&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;avg&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;aggregate&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;params&amp;quot;: [&lt;br /&gt;
                  &amp;quot;value&amp;quot;&lt;br /&gt;
                ],&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;alias&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
          ],&lt;br /&gt;
          &amp;quot;table&amp;quot;: &amp;quot;history&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumn&amp;quot;: &amp;quot;TIMESTAMP&amp;quot;,&lt;br /&gt;
          &amp;quot;timeColumnType&amp;quot;: &amp;quot;timestamp&amp;quot;,&lt;br /&gt;
          &amp;quot;where&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;$__timeFilter&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;macro&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;DEVICE&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_1&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              &amp;quot;datatype&amp;quot;: &amp;quot;varchar&amp;quot;,&lt;br /&gt;
              &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
              &amp;quot;params&amp;quot;: [&lt;br /&gt;
                &amp;quot;READING&amp;quot;,&lt;br /&gt;
                &amp;quot;=&amp;quot;,&lt;br /&gt;
                &amp;quot;&#039;WR_2_West&#039;&amp;quot;&lt;br /&gt;
              ],&lt;br /&gt;
              &amp;quot;type&amp;quot;: &amp;quot;expression&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
          ]&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;thresholds&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeFrom&amp;quot;: null,&lt;br /&gt;
      &amp;quot;timeRegions&amp;quot;: [],&lt;br /&gt;
      &amp;quot;timeShift&amp;quot;: null,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Forecast/Prognose&amp;quot;,&lt;br /&gt;
      &amp;quot;tooltip&amp;quot;: {&lt;br /&gt;
        &amp;quot;shared&amp;quot;: true,&lt;br /&gt;
        &amp;quot;sort&amp;quot;: 0,&lt;br /&gt;
        &amp;quot;value_type&amp;quot;: &amp;quot;individual&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;graph&amp;quot;,&lt;br /&gt;
      &amp;quot;xaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;buckets&amp;quot;: null,&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;time&amp;quot;,&lt;br /&gt;
        &amp;quot;name&amp;quot;: null,&lt;br /&gt;
        &amp;quot;show&amp;quot;: true,&lt;br /&gt;
        &amp;quot;values&amp;quot;: []&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;yaxes&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;decimals&amp;quot;: 0,&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: &amp;quot;Watt&amp;quot;,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: &amp;quot;16000&amp;quot;,&lt;br /&gt;
          &amp;quot;min&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;format&amp;quot;: &amp;quot;short&amp;quot;,&lt;br /&gt;
          &amp;quot;label&amp;quot;: null,&lt;br /&gt;
          &amp;quot;logBase&amp;quot;: 1,&lt;br /&gt;
          &amp;quot;max&amp;quot;: null,&lt;br /&gt;
          &amp;quot;min&amp;quot;: null,&lt;br /&gt;
          &amp;quot;show&amp;quot;: true&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;yaxis&amp;quot;: {&lt;br /&gt;
        &amp;quot;align&amp;quot;: false,&lt;br /&gt;
        &amp;quot;alignLevel&amp;quot;: null&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;refresh&amp;quot;: &amp;quot;5m&amp;quot;,&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 27,&lt;br /&gt;
  &amp;quot;style&amp;quot;: &amp;quot;dark&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [],&lt;br /&gt;
  &amp;quot;templating&amp;quot;: {&lt;br /&gt;
    &amp;quot;list&amp;quot;: []&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;time&amp;quot;: {&lt;br /&gt;
    &amp;quot;from&amp;quot;: &amp;quot;now-1d/d&amp;quot;,&lt;br /&gt;
    &amp;quot;to&amp;quot;: &amp;quot;now-1d/d&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timepicker&amp;quot;: {&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;refresh_intervals&amp;quot;: [&lt;br /&gt;
      &amp;quot;5s&amp;quot;,&lt;br /&gt;
      &amp;quot;10s&amp;quot;,&lt;br /&gt;
      &amp;quot;30s&amp;quot;,&lt;br /&gt;
      &amp;quot;1m&amp;quot;,&lt;br /&gt;
      &amp;quot;5m&amp;quot;,&lt;br /&gt;
      &amp;quot;15m&amp;quot;,&lt;br /&gt;
      &amp;quot;30m&amp;quot;,&lt;br /&gt;
      &amp;quot;1h&amp;quot;,&lt;br /&gt;
      &amp;quot;2h&amp;quot;,&lt;br /&gt;
      &amp;quot;1d&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;timezone&amp;quot;: &amp;quot;utc&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;PV_Anlage_1&amp;quot;,&lt;br /&gt;
  &amp;quot;uid&amp;quot;: &amp;quot;W-Y51Dmgk&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: 105&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Diagramme mit SVG==&lt;br /&gt;
Die Diagramme werden bei mir nicht mehr weiterentwickelt, da ich auf Grafana umgestiegen bin. Sie stehen hier nur noch als Beispiele für den Anfang.&lt;br /&gt;
Grafana ermöglicht das direkte Auslesen der SQL Datenbank und kann auch auf einer anderen Plattform betrieben werden. Bei mir befindet es sich in Docker Containern auf dem selben RPI4.&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Total_PV_P_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P:::$val=abs($val)&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_Battery::&lt;br /&gt;
#LogDB WR_1:SW_Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB WR_1:SW_Actual_battery_charge_usable_P::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_Max::&lt;br /&gt;
#LogDB WR_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:max_month_SW_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB WR_1_API:diff_week_SW_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SW_Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB WR_1_API:SW_Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_&amp;lt;Wohnort&amp;gt;_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB WR_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB WR_1:SW_Total_DC_P_sumOfAllPVInputs::&lt;br /&gt;
#LogDB WR_1:Solar_Calculation::&lt;br /&gt;
#LogDB WR_1:Solar_East::&lt;br /&gt;
#LogDB WR_1:Solar_South::&lt;br /&gt;
#LogDB WR_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power_(sumOfAllPVInputs)&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
&#039;&#039;&#039;Hier werde ich auch mal aktualisieren, bei bedarf einfach im Forum fragen.&#039;&#039;&#039;&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe Novelan LAD ===&lt;br /&gt;
Hier mal ein paar Bilder für die Dokumentation der PV-Modus Anschaltung mit einem Shell 1 und das Heizelement, dass man über Lastrelais in drei Stufen Regeln könnte. Die Aktivierung der Zusatzheizung ist über das Luxtronik2 Modul möglich.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
LAD_Zusatzheizung_2_4_6_kW.jpg|Zusatzheizung 2/4/6 kW&lt;br /&gt;
LAD_Shelly_Einbauposition.jpg|LAD Shelly Einbauposition&lt;br /&gt;
LAD_Shelly_Phase_und_Null.jpg|LAD Shelly Phase und Null&lt;br /&gt;
LAD_Shelly_SWT-Signal.jpg|LAD Shelly SWT-Signal&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV_Perl (DOIF Modul) ====&lt;br /&gt;
Hierbei wird das PV-Modus Signal über ein Shelly 1 zur LAD Wärmepumpe übermittelt, was natürlich auch durch ein beliebiges anderes Relais erfolgen kann.&lt;br /&gt;
Die setstate Attribute am Ende der RAW Definition sind ebenfalls wichtig, da dort die Default reading Werte für das DOIF gesetzt werden. Diese können dann über die uiTable Definitionen mit Pull Down Menüs geändert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 1                                   ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                     ## Die LWP ist aus\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]           ## Die maximale Laufzeit der LWP ist noch nicht erreicht\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## Das Maximum des PV-Modus ist noch nicht erreicht\&lt;br /&gt;
     and [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]   ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : LWP on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;LWP_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;PV_Modus_Ein_LWP();;set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;)&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : LWP on for manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : LWP off after manuel PV-Modus&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]          ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : LWP off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; 100                              ## es soll noch eine Reserve bleiben\&lt;br /&gt;
     and [LWP_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]          ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;                                      ## Die LWP Läuft\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : LWP off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;gt; 0                                  ## läuft eine Wartezeit\&lt;br /&gt;
     and get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;) &amp;lt; 5                                  ## läuft die Wartezeit bald ab\&lt;br /&gt;
     and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and [$SELF:LWP_Status] eq &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot;\&lt;br /&gt;
      and [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
     or                              ## eventuell läuft die LWP bereits an, dann muss auch der timer gestoppt werden\&lt;br /&gt;
     (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300\&lt;br /&gt;
      and [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe läuft&amp;quot;\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer LWP &amp;quot;.get_Exec(&amp;quot;LWP_Ein_timer&amp;quot;)};;\&lt;br /&gt;
    del_Exec(&amp;quot;LWP_Ein_timer&amp;quot;);;                                           ## Die LWP wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
## Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_1_LWP_Nachheizen_WW\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [[$SELF:TimeEnd]]                                               ## Am Ende der möglichen PV Steuerung\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt;= 48                             ## wenn das Wasser noch nicht im Sollbereich ist\&lt;br /&gt;
     and\&lt;br /&gt;
        (   [LWP_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]        ## Die maximale Laufzeit der LWP/Tag ist noch nicht erreicht\&lt;br /&gt;
         or [LWP_Counter:countsPerDay] eq 0)                             ## oder die LWP ist noch gar nicht gelaufen\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_LWP_Nachheizen_WW&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP on for water heating&amp;quot;};;\&lt;br /&gt;
                                                                         ## Es wird die Soll Temperatur um die Hysterese angehoben \&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget &amp;quot;.(ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,48)+4));;\&lt;br /&gt;
                                                                         ## Das zurücksetzen auf den Standard von 50° erfolgt generell beim Abschalten\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_1 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Hohe Priorität im Winter für die LWP\&lt;br /&gt;
## Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
04_2_LWP_Prioritaet_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMaxSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
     and [WR_1:SW_Total_PV_P_reserve] &amp;gt;= 2000                            ## es besteht jedoch noch eine Reserve und der\&lt;br /&gt;
     and [shelly02:power_0] &amp;gt; 800                                        ## Pool wird gerade aufgeheizt, was im Winter auch in der Nacht passiert\&lt;br /&gt;
     and [WR_1:Act_state_of_charge] &amp;gt; 60                                 ## Der Speicher sollte schon 60 % gefüllt sein\&lt;br /&gt;
     and [Heizung:hotWaterTemperature] &amp;lt; 60                              ## und die WW Temperatur noch unter 60°\&lt;br /&gt;
     and [$SELF:LWP_Priority] eq &amp;quot;frei&amp;quot;                                  ## Aber nur einmal am Tag\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_LWP_Prioritaet_An&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 04_2 : LWP Priorität&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Ein_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___LWP_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:LWP_Status] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
        or [$SELF:LWP_Status] eq &amp;quot;manuell&amp;quot;\&lt;br /&gt;
       )\&lt;br /&gt;
     and [LWP_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimeMin]\&lt;br /&gt;
     and ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___LWP_Ende&amp;quot;                           ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 05__ : LWP run finished&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_LWP();;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Priorität für LWP wieder frei geben, damit einmal am Tag der PV-Modus verwendet werden kann\&lt;br /&gt;
##\&lt;br /&gt;
06___LWP_Prioritaet_Reset\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [23:55]\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;06___LWP_Prioritaet_Reset&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 06__ : LWP Priorität frei&amp;quot;};;\&lt;br /&gt;
     set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;frei&amp;quot;);;                                 ## Der PV-Modus darf wieder verwendet weden\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## In der Überganszeit wird die Heizung kurz vor der PV-Zeit wieder ein geschaltet\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_1_Heizung_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeStartHeizung]]                                        ## Einschalten der Heizung, damit aus dem Puffer nachgeheizt wird 02:03\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_1_Heizung_An&amp;quot;                         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_1 : LWP Heizung Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHeating Auto&amp;quot;);;                  ## Die Heizungssteuerung erfolgt wieder Automatisch\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Während des Winters kann man die Heizung bis in die Morgenstunden ganz abschalten (Accu sparen)\&lt;br /&gt;
##\&lt;br /&gt;
07_2_Heizung_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [[$SELF:TimeEndHeizung]]                                          ## Abschalten der Heizung, damit der Puffer für morgens Heizreserve hat\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;07_2_Heizung_Aus&amp;quot;                        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 07_2 : LWP Heizung aus&amp;quot;};;\&lt;br /&gt;
   ::CommandSet(undef, &amp;quot;Heizung opModeHeating Off&amp;quot;);;                     ## Die Heizung wird komplett abgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
   if (    [WR_1:Solar_Calculation_fc1_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] ## Auch morgen ist das Wetter schlecht\&lt;br /&gt;
       and [Heizung:averageAmbientTemperature] &amp;lt;= 5.6 ) {                ## Die Heizgrenze ist schon ziemlich tief\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungWinter]);;    ## Im Winter bis in die Morgenstunden den Accu sparen\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
         {Log 3, &amp;quot;$SELF 07_2 : Parameter: &amp;quot;.[WR_1:Solar_Calculation_fc1_day].&amp;quot; &amp;lt; &amp;quot;.[WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit].&amp;quot; and &amp;quot;.[Heizung:averageAmbientTemperature].&amp;quot; &amp;lt;= 5.6&amp;quot;};;\&lt;br /&gt;
     } else {\&lt;br /&gt;
      set_Reading(&amp;quot;TimeStartHeizung&amp;quot;,[$SELF:TimeStartHeizungUebergang]);; ## Bei schönerem Wetter erst später Heizen\&lt;br /&gt;
     }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_2 : TimeStartHeizung switched to &amp;quot;.[$SELF:TimeStartHeizung]};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 15°\&lt;br /&gt;
##\&lt;br /&gt;
07_3_Heizung_WZ_15_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_3_Heizung_WZ_15_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_3 : Heizung WZ 15 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 15&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Heizung im Wohnzimmer auf 22°\&lt;br /&gt;
##\&lt;br /&gt;
07_4_Heizung_WZ_22_Grad\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_4_Heizung_WZ_22_Grad&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_4 : Heizung WZ 22 Grad&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Thermostat_WO desired-temp 22&amp;quot;);;               ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung aus\&lt;br /&gt;
##\&lt;br /&gt;
07_5_Warmwasser_aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_5_Warmwasser_aus&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_5 : LWP Warmwasser aus&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Off&amp;quot;);;                  ## Die Warmwasserbereitung wird ausgeschaltet\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation inactive&amp;quot;);;                      ## Zirkulation ebenfalls abschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Warmwasser Bereitung auf Automatik\&lt;br /&gt;
##\&lt;br /&gt;
07_6_Warmwasser_an\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;07_6_Warmwasser_an&amp;quot;                      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 07_6 : LWP Warmwasser Automatik&amp;quot;};;\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung opModeHotWater Auto&amp;quot;);;                 ## Die Warmwassersteuerung erfolgt wieder automatisch\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;n_Zirkulation active&amp;quot;);;                        ## Zirkulation wieder einschalten\&lt;br /&gt;
     ::CommandSet(undef, &amp;quot;Heizung statusRequest&amp;quot;);;                       ## Einen aktuellen Status abholen\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_LWP() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP on&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 60.0&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;LWP_Priority&amp;quot;,&amp;quot;verwendet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_LWP() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : LWP off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    ::CommandSet(undef, &amp;quot;Heizung hotWaterTemperatureTarget 50.0&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr LWP_PV_Perl DbLogExclude .*&lt;br /&gt;
attr LWP_PV_Perl DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV_Perl alias LWP_PV_Perl&lt;br /&gt;
attr LWP_PV_Perl comment Version 2023.01.18 09:00&lt;br /&gt;
attr LWP_PV_Perl disable 0&lt;br /&gt;
attr LWP_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV_Perl icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV_Perl room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV_Perl sortby 411&lt;br /&gt;
attr LWP_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|::ReadingsTimestamp(&amp;quot;Heizung&amp;quot;,&amp;quot;counterHeatQTotal&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;&amp;lt;dd&amp;gt;Status / LWP Status / Brauchwasser&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,04_1_LWP_Nachheizen_WW,04_2_LWP_Prioritaet_An,05___LWP_Ende,06___LWP_Prioritaet_Reset,07_1_Heizung_An,07_2_Heizung_Aus,07_3_Heizung_WZ_15_Grad,07_4_Heizung_WZ_22_Grad,07_5_Warmwasser_aus,07_6_Warmwasser_an&amp;quot;) |[Heizung:opStateHeatPump1].&amp;quot; &amp;quot;.[Heizung:opStateHeatPump2]|[Heizung:opStateHeatPump3]|FUNC_Status([Heizung:hotWaterTemperature],47,&amp;quot;orange&amp;quot;,[Heizung:hotWaterTemperature],&amp;quot;green&amp;quot;,[Heizung:hotWaterTemperature],53,&amp;quot;red&amp;quot;,[Heizung:hotWaterTemperature]).&amp;quot; °C&amp;quot;\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,1000,250,4000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;PV-Modus / Heiz-Modus / Winter, Übergangszeit Heiz Start/Ende&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;PV-Modus:&amp;lt;br&amp;gt;&amp;quot;.[$SELF:LWP_Priority].&amp;quot; / &amp;quot;.(([$SELF:LWP_Status] ne &amp;quot;Aus&amp;quot;)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;&#039;.[$SELF:LWP_Status].&#039;&amp;lt;/span&amp;gt;&#039;)|&amp;quot;Heizung: &amp;quot;.[Heizung:opModeHeating].&amp;quot;&amp;lt;br&amp;gt;Warmwasser: &amp;quot;.[Heizung:opModeHotWater]|widget([$SELF:TimeStartHeizungWinter],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartHeizungUebergang],&amp;quot;time&amp;quot;)|[$SELF:TimeStartHeizung].widget([$SELF:TimeEndHeizung],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;Statistiken&amp;quot;|&amp;quot;Zähler&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Information&amp;quot;|&amp;quot;Wert&amp;quot;\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;EVU&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[EVU_StromZaehler:Strom_Status-02])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;LWP/KWL&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung_Zaehler])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Heizung&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHeating])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Warmwasser&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQHotWater])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Photovoltaik&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQPool])\&lt;br /&gt;
|&amp;quot;&amp;quot;|&amp;quot;LWP&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;Gesamt&amp;quot;|sprintf(&amp;quot;%06d kWh&amp;quot;,[Heizung:counterHeatQTotal])\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 23:55:00 LWP_Priority frei&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-29 15:37:06 LWP_Status Aus&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 12:21:48 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 3000&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 2250&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-25 19:00:12 RunTimeMin 2400&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:55:35 RunTimePerDay 28800&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:37 TimeEnd 15:05&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 13:24:01 TimeEndHeizung 18:35&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-10 15:50:19 TimeStart 11:30&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-30 18:35:00 TimeStartHeizung 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:37:59 TimeStartHeizungUebergang 09:50&lt;br /&gt;
setstate LWP_PV_Perl 2022-05-13 16:34:08 TimeStartHeizungWinter 02:05&lt;br /&gt;
&lt;br /&gt;
setstate LWP_PV_Perl 2022-10-31 12:05:34 ui_command_1 ---&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.54&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP&lt;br /&gt;
attr shelly01 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 412&lt;br /&gt;
attr shelly01 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung_Zaehler&amp;quot;,0));;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal(&amp;quot;StromZaehler_Heizung&amp;quot;,&amp;quot;SMAEM1901401955_Bezug_Wirkleistung&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Wärmepumpe Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly01 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{4}(\.[0-9]{1})*$ StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:\s-[0-9]{1,3}(\.[0-9]{1})*$&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter comment Version 2021.01.09 11:16&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 413&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool Softube ===&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;Aus&amp;quot;                                    ## Der Pool ist aus\&lt;br /&gt;
     and [Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay]          ## Die maximale Laufzeit des Pools ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 01_1 : Pool on waiting&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;An&amp;quot;);;PV_Modus_Ein_Pool()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot; ) {      ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_2 : Pool on for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell den Pool abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
       [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 01_3 : Pool off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Pool_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay]         ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and (   [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                 ## Der Pool läuft\&lt;br /&gt;
          or [$SELF:Pool_Status] eq &amp;quot;pflege&amp;quot;)\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_1 : Pool off Laufzeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [WR_1:Home_own_consumption_from_grid]                           ## Nicht zuviel Bezug aus dem Netz\&lt;br /&gt;
       + [WR_1:Home_own_consumption_from_Battery]) &amp;gt; 100                  ## oder dem Speicher\&lt;br /&gt;
     and [Pool_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin]         ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Pool_Status] eq &amp;quot;An&amp;quot;                                     ## Der Pool läuft (nicht bei manuell)\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;Pool_PV 02_2 : Pool off PV-Min&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 5                             ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Wartend&amp;quot;                               ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 03__ : Stop wait timer Pool&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Der Pool wird nicht mehr eingeschaltet\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
05___Pool_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly02:power_0] &amp;lt; 10                                         ## Die Poolpumpe ist bereits\&lt;br /&gt;
     and [Pool_Counter:pauseTimeIncrement] &amp;gt; 900                         ## seit 5 Minuten aus\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Aus&amp;quot;                                    ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Pool_Status] ne &amp;quot;Wartend&amp;quot;                                ## und es wird nicht wegen eines Peaks gewartet\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05___Pool_Ende&amp;quot;                          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV 05__ : Pool run finished &amp;quot;.[shelly02:power_0].&amp;quot; &amp;quot;.[Pool_Counter:pauseTimeIncrement]};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit] or\&lt;br /&gt;
       [Heizung:averageAmbientTemperature] &amp;lt;= 10 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 08__ : Pool switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
09___Laufzeit_im_Sommer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
         [06:15] and [Heizung:averageAmbientTemperature]                 ## Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot;               ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;09___Laufzeit_im_Sommer&amp;quot; ) {             ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [Heizung:averageAmbientTemperature] &amp;gt;= 18 ) {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDaySummer]);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;RunTimePerDay&amp;quot;,[$SELF:RunTimePerDayWinter]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 09__ : Pool switched to RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;RunTimePerDay&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
10___Pool_Pflege\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [[$SELF:TimeEnd]]                                                 ## Hier sollte der Pool bereits gelaufen sein\&lt;br /&gt;
      and\&lt;br /&gt;
       ([Pool_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] or        ## Ist er zuwenig gelaufen\&lt;br /&gt;
        [Pool_Counter:countsPerDay] eq 0)                                ## oder eventuell garnicht\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot;                       ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;10___Pool_Pflege&amp;quot; ) {                    ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on for maintanance&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;pflege&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Im Herbst Winter den Pool bei günstigem Strom in der Nacht zusätzlich einschalten\&lt;br /&gt;
##\&lt;br /&gt;
11___Nachtstrom_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;onx&amp;quot;                           ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [22:00-05:00]                                                  ## nur in dieser Zeit verwenden\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot;                     ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;11___Nachtstrom_An&amp;quot; ) {                  ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool on Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Nachtstrom&amp;quot;);;\&lt;br /&gt;
   PV_Modus_Ein_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Sobald der Strompreis wieder teurer wird den Pool abschalten\&lt;br /&gt;
##\&lt;br /&gt;
12___Nachtstrom_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     ( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]  ## Im Herbst/Winter ist wenig zu erwarten\&lt;br /&gt;
      and [EVU_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot;                          ## Gibt es günstigen Strom an der Börse\&lt;br /&gt;
      and [$SELF:Pool_Status] eq &amp;quot;Nachtstrom&amp;quot;                            ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
     or [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {                                                              \&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;12___Nachtstrom_Aus&amp;quot; ) {                 ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV 10__ : Pool off after Nachtstrom by aWATTar&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
   PV_Modus_Aus_Pool();;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Pool() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool on&amp;quot;};;\&lt;br /&gt;
##     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}  ## das sollte eigentlich raus\&lt;br /&gt;
    fhem(&amp;quot;set Pool_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Pool() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;Pool_PV sub  : Pool off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Pool_Status&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Pool_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Pool_PV_Perl alias Pool_PV_Perl&lt;br /&gt;
attr Pool_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Pool_PV_Perl disable 0&lt;br /&gt;
attr Pool_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Pool_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV_Perl icon scene_swimming&lt;br /&gt;
attr Pool_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV_Perl sortby 421&lt;br /&gt;
attr Pool_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Pumpe Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_abschalten_Laufzeit,02_2_Eigenverbrauch_abschalten_PV_Min,03___Stop_Wait_Timer,05___Pool_Ende,08___Startzeit_nach_forecast,09___Laufzeit_im_Sommer,10___Pool_Pflege,11___Nachtstrom_An,12___Nachtstrom_Aus&amp;quot;) |[$SELF:Pool_Status]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly02:power_0] &amp;gt; 10)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Pool_Pumpe_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Pool_Pumpe_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,100,50,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,50,50,2000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter / RunTimePerDay / Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|widget([$SELF:RunTimePerDaySummer],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimePerDayWinter],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Pool_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 16:44:33 Pool_Status Aus&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:47 PowerLevelMinTime 300&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:51:44 PowerLimitOff 100&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:50:44 PowerLimitOn 1000&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 15:55:23 RunTimeMin 7200&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 06:15:00 RunTimePerDay 28800&lt;br /&gt;
setstate Pool_PV_Perl 2021-06-23 14:55:42 RunTimePerDaySummer 7200&lt;br /&gt;
setstate Pool_PV_Perl 2020-10-06 14:14:13 RunTimePerDayWinter 28800&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:06 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-05-10 16:23:24 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeEnd 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-01 17:39:32 TimeEndSummer 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2021-12-05 14:20:48 TimeEndWinter 16:00&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-23 07:17:00 TimeStart 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2022-06-30 12:48:23 TimeStartSummer 12:35&lt;br /&gt;
setstate Pool_PV_Perl 2020-09-03 13:10:56 TimeStartWinter 09:10&lt;br /&gt;
&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-30 11:25:40 ui_command_1 ---&lt;br /&gt;
setstate Pool_PV_Perl 2022-10-16 19:59:44 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool&lt;br /&gt;
attr shelly02 comment Version 2020.10.19 18:28\&lt;br /&gt;
relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,energy.*,state,network&lt;br /&gt;
attr shelly02 event-on-update-reading power.*&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 422&lt;br /&gt;
attr shelly02 stateFormat {\&lt;br /&gt;
my $status = (ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_0_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_0&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
my $e1 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_1_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r1 = (ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p1 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power_1&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    Status: $status\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Pool Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
     JEL Gesamt 1: $e1&amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: $r1 $p1\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly02 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_0_Total:energy_0.* monotonic { ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0) },\&lt;br /&gt;
energy_1_Total:energy_1.* monotonic { ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0) }\&lt;br /&gt;
&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV_Perl DOIF ################################################################################################################\&lt;br /&gt;
## Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
01_1_Eigenverbrauch_automatisch_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;gt;= [$SELF:PowerLimitOn]            ## Es besteht PV-Überschuss\&lt;br /&gt;
     and [[$SELF:TimeStart]-[$SELF:TimeEnd]]                             ## Das Zeitfenster ist erreicht\&lt;br /&gt;
     and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; 1                              ## Der Wait Timer ist noch nicht gestartet\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;                                       ## Die Waschmaschine ist aus\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [$SELF:RunTimePerDay] ## Die maximale Laufzeit der Waschmaschine ist noch nicht erreicht\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_1_Eigenverbrauch_automatisch_An&amp;quot;      ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 01_1 : Waiting for &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minutes&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;,[$SELF:PowerLevelMinTime],&#039;set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;An&amp;quot;);;set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss An&amp;quot;);;PV_Modus_Ein_Waschmaschine()&#039;);; ## Den PV-Modus verzögert einschalten\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;für &amp;quot;.([$SELF:PowerLevelMinTime]/60).&amp;quot; Minuten&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuell das Gerät einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_2_Eigenverbrauch_manuell_An\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [$SELF:Status_1] eq &amp;quot;Aus&amp;quot;\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;on&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_2_Eigenverbrauch_manuell_An&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_2 : On for manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;manuell&amp;quot;);;\&lt;br /&gt;
    PV_Modus_Ein_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell An&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Manuelle Verwendung abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
01_3_Eigenverbrauch_manuell_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    ( (   [$SELF:Status_1] eq &amp;quot;An&amp;quot;\&lt;br /&gt;
       or [$SELF:Status_1] eq &amp;quot;manuell&amp;quot;)\&lt;br /&gt;
     and [shelly03:relay] eq &amp;quot;off&amp;quot;                                        ## Der Taster wurde gedrückt\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;01_3_Eigenverbrauch_manuell_Aus&amp;quot;         ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 01_3 : Off after manuel usage&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose manuell Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
02_1_Eigenverbrauch_Laufzeit_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [$SELF:RunTimePerDay] ## Die Tages Laufzeit ist überschritten\&lt;br /&gt;
     and [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [$SELF:RunTimeMin] ## Die Mindestlaufzeit ist überschritten\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## Das Gerät läuft\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_1_Eigenverbrauch_Laufzeit_Aus&amp;quot;        ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_1 : Off by runtime&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Laufzeit Max Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Eigenverbrauch abschalten: falls die Waschmaschine doch nicht benötigt wurde\&lt;br /&gt;
##\&lt;br /&gt;
02_2_Eigenverbrauch_PV_Min_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]             ## Der Überschuss ist zu wenig\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und die Waschmaschine wartet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;                     ##   auf den start\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;02_2_Eigenverbrauch_PV_Min_Aus&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
     if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 02_2 : PV-Minimum unterschritten&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Min Aus&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
## wenn während der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
03___Stop_Wait_Timer\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (\&lt;br /&gt;
     (    [WR_1:SW_Total_PV_P_reserve] &amp;lt; [$SELF:PowerLimitOn]            ## Ist die PV-Leistung zu niedrig?\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;gt; 0                             ## läuft eine Wartezeit\&lt;br /&gt;
      and get_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;) &amp;lt; [$SELF:PowerLevelMinTime]     ## läuft die Wartezeit bald ab\&lt;br /&gt;
      and [$SELF:Status_1] eq &amp;quot;Wartend&amp;quot;                                  ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     )\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;03___Stop_Wait_Timer&amp;quot;                    ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 03__ : Stop wait timer&amp;quot;};;\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;warten gestoppt&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_1_Waschprogramm_wartend\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;lt; 1                                            ## Das Gerät ist bereits\&lt;br /&gt;
     and [Waschmaschine_Counter:pauseTimeIncrement] &amp;gt; 120                ## seit 2 Minuten aus\&lt;br /&gt;
     and [$SELF:Status_1] eq &amp;quot;An&amp;quot;                                        ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and\&lt;br /&gt;
       (   [$SELF:Status_2] eq &amp;quot;PV Überschuss An&amp;quot;                        ## falls die Waschmaschine nicht gebraucht\&lt;br /&gt;
        or [$SELF:Status_2] eq &amp;quot;PV Überschuss wartend&amp;quot;)                  ## wird einfach weiter warten\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_1_Waschprogramm_wartend&amp;quot;              ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 04_1 : Waschmaschine ist nicht gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;PV Überschuss wartend&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
04_2_Waschprogramm_gestartet\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] &amp;gt; 0                                            ## Das Gerät ist bereits gestartet\&lt;br /&gt;
##     and [shelly03:power_Waschmaschine_avg] &amp;lt; 70                         ## und verbraucht mehr Leistung als im Standby\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestartet&amp;quot;                   ## \&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;04_2_Waschprogramm_gestartet&amp;quot;            ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF 04_2 : Waschprogramm gestartet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm gestartet&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist gestartet&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Ende\&lt;br /&gt;
##\&lt;br /&gt;
05_1_Waschprogramm_Ende\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [shelly03:power] == 0                                           ## Die Waschmaschine hat abgeschaltet\&lt;br /&gt;
     and [$SELF:Status_2] eq &amp;quot;Waschprogramm gestartet&amp;quot;                   ## und vorher lief das Waschprogramm\&lt;br /&gt;
\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;                 ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
      set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Waschprogramm beendet&amp;quot;);;\&lt;br /&gt;
      fhem(&amp;quot;set alias=Mobil speak 40 Das Waschprogramm ist fertig&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
      if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
        {Log 3, &amp;quot;$SELF 05_1 : Waschprogramm beendet&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
    \&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_1_Waschprogramm_Ende&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Gerät Abschalten, wenn es nicht verwendet wurde\&lt;br /&gt;
##\&lt;br /&gt;
05_2_Waschmaschine_Aus\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
    and\&lt;br /&gt;
    (    [[$SELF:TimeEnd]-[$SELF:TimeStart]]                             ## und auch nicht in der Nachtzeit\&lt;br /&gt;
     and [$SELF:Status_1] ne &amp;quot;manuell&amp;quot;                                   ## und gibt es keine manuelle Einschaltung\&lt;br /&gt;
     and [$SELF:Status_2] ne &amp;quot;Waschprogramm gestarted&amp;quot;                   ## und es läuft kein Waschprogramm\&lt;br /&gt;
     and [$SELF:ui_command_1] eq &amp;quot;---&amp;quot;\&lt;br /&gt;
    )\&lt;br /&gt;
    or [$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;                  ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
   ) {\&lt;br /&gt;
\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
      {Log 3, &amp;quot;$SELF 05_2 : Keine PV-Zeit&amp;quot;};;\&lt;br /&gt;
\&lt;br /&gt;
    del_Exec(&amp;quot;PV_Modus_Ein_timer&amp;quot;);;                                      ## Das Gerät wird nicht mehr eingeschaltet\&lt;br /&gt;
    PV_Modus_Aus_Waschmaschine();;\&lt;br /&gt;
\&lt;br /&gt;
    if ([$SELF:ui_command_1] eq &amp;quot;05_2_Waschmaschine_Aus&amp;quot;) {\&lt;br /&gt;
      set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                           ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
    }\&lt;br /&gt;
   }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Geräte Startzeit durch Forecast verschieben. Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
##\&lt;br /&gt;
08___Startzeit_nach_forecast\&lt;br /&gt;
{if( !([$SELF:state] eq &amp;quot;off&amp;quot;)                                           ## DOIF enabled\&lt;br /&gt;
     and\&lt;br /&gt;
     (\&lt;br /&gt;
         [07:17]                                                         ## Der Forecast wird um 7:00 im Device PV_Schedule aktualisiert\&lt;br /&gt;
      or [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot;          ## Hier wird das uiTable select ausgewertet\&lt;br /&gt;
     )\&lt;br /&gt;
   ) {\&lt;br /&gt;
   if( [$SELF:ui_command_1] eq &amp;quot;08___Startzeit_nach_forecast&amp;quot; ) {        ## Hier wurde manuell eingeschaltet\&lt;br /&gt;
     set_Reading(&amp;quot;ui_command_1_before&amp;quot;,[$SELF:ui_command_1]);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if( [WR_1:Solar_Calculation_fc0_day] &amp;lt; [WR_1_Speicher_1_ExternControl:SpeicherMinSOC_fc1_Limit]) {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndWinter]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Winter&amp;quot;);;\&lt;br /&gt;
   } else {\&lt;br /&gt;
     set_Reading(&amp;quot;TimeStart&amp;quot;,[$SELF:TimeStartSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;TimeEnd&amp;quot;,[$SELF:TimeEndSummer]);;\&lt;br /&gt;
     set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Startzeit für Sommer&amp;quot;);;\&lt;br /&gt;
   }\&lt;br /&gt;
\&lt;br /&gt;
   if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
     {Log 3, &amp;quot;$SELF 08__ : Switched to TimeStart &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeStart&amp;quot;,0).&amp;quot; TimeEnd &amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;TimeEnd&amp;quot;,0)};;\&lt;br /&gt;
\&lt;br /&gt;
   set_Reading(&amp;quot;ui_command_1&amp;quot;,&amp;quot;---&amp;quot;);;                                    ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\&lt;br /&gt;
                                                                         ## kann das Kommando nicht sofort wiederholt werden\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## Definition von Sub Routinen\&lt;br /&gt;
subs {\&lt;br /&gt;
  sub PV_Modus_Ein_Waschmaschine() {                                                   ## PV-Modus Einschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : On&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;set Waschmaschine_Counter pauseTimeIncrement 0&amp;quot;);;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0));;\&lt;br /&gt;
    }\&lt;br /&gt;
\&lt;br /&gt;
  sub PV_Modus_Aus_Waschmaschine() {                                                   ## PV-Modus Ausschalten\&lt;br /&gt;
    if (AttrVal(&amp;quot;$SELF&amp;quot;,&amp;quot;verbose&amp;quot;,0) &amp;gt;=3)\&lt;br /&gt;
       {Log 3, &amp;quot;$SELF sub  : Off&amp;quot;};;\&lt;br /&gt;
    fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;$SELF&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0));;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_1&amp;quot;,&amp;quot;Aus&amp;quot;);;\&lt;br /&gt;
    set_Reading(&amp;quot;Status_2&amp;quot;,&amp;quot;Steckdose ist ausgeschaltet&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}&lt;br /&gt;
attr Waschmaschine_PV_Perl DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV_Perl alias Waschmaschine_PV_Perl&lt;br /&gt;
attr Waschmaschine_PV_Perl comment Version 2021.11.01 09:00&lt;br /&gt;
attr Waschmaschine_PV_Perl disable 0&lt;br /&gt;
attr Waschmaschine_PV_Perl event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_PV_Perl event_Readings Status_1:[$SELF:Status_1], Status_2:[$SELF:Status_2]&lt;br /&gt;
attr Waschmaschine_PV_Perl group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV_Perl icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV_Perl room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV_Perl sortby 4311&lt;br /&gt;
attr Waschmaschine_PV_Perl uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
  $TABLE = &amp;quot;style=&#039;width:100%;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{0}     = &amp;quot;align=&#039;center&#039; style=&#039;font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
  $TD{0..9}{1} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{2..4} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
  $TD{0..9}{5} = &amp;quot;style=&#039;border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
sub FUNC_Status {\&lt;br /&gt;
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\&lt;br /&gt;
    my $ret = ($value &amp;lt; $min)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMin.&#039;&amp;quot;&amp;gt;&#039;.$statusMin.&#039;&amp;lt;/span&amp;gt;&#039; : ($value &amp;gt; $max)? &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMax.&#039;&amp;quot;&amp;gt;&#039;.$statusMax.&#039;&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:&#039;.$colorMiddel.&#039;&amp;quot;&amp;gt;&#039;.$statusMiddle.&#039;&amp;lt;/span&amp;gt;&#039;;;\&lt;br /&gt;
    return $ret;;\&lt;br /&gt;
  }\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;$SELF&amp;quot;|&amp;quot;Kommando&amp;lt;dd&amp;gt;Auswahl / Status /  / Waschmaschine Status&amp;lt;/dd&amp;gt;&amp;quot; |widget([$SELF:ui_command_1],&amp;quot;uzsuDropDown,---,01_1_Eigenverbrauch_automatisch_An,01_2_Eigenverbrauch_manuell_An,01_3_Eigenverbrauch_manuell_Aus,02_1_Eigenverbrauch_Laufzeit_Aus,02_2_Eigenverbrauch_PV_Min_Aus,03___Stop_Wait_Timer,04_1_Waschprogramm_wartend,04_2_Waschprogramm_gestartet,05_1_Waschprogramm_Ende,05_2_Waschmaschine_Aus,08___Startzeit_nach_forecast&amp;quot;) |[$SELF:Status_1].&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.[$SELF:Status_2]|::ReadingsTimestamp(&amp;quot;$SELF&amp;quot;,&amp;quot;timer_PV_Modus_Ein_timer&amp;quot;,&amp;quot;&amp;quot;)|(([shelly03:power] &amp;gt; 7)?&#039;&amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Waschmaschine_laeuft&amp;lt;/span&amp;gt;&#039; : &#039;&amp;lt;span style=&amp;quot;color:black&amp;quot;&amp;gt;Waschmaschine_aus&amp;lt;/span&amp;gt;&#039;)\&lt;br /&gt;
|&amp;quot;Konfiguration&amp;lt;dd&amp;gt;PowerLevelMinTime, | PowerLimit On/Off | Time Start/End&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;RunTime Min/PerDay&amp;lt;/dd&amp;gt;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:PowerLevelMinTime],&amp;quot;selectnumbers,60,60,900,0,lin&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;.widget([$SELF:RunTimeMin],&amp;quot;selectnumbers,300,300,7200,0,lin&amp;quot;).widget([$SELF:RunTimePerDay],&amp;quot;selectnumbers,900,300,28800,0,lin&amp;quot;)|widget([$SELF:PowerLimitOn],&amp;quot;selectnumbers,250,250,2000,0,lin&amp;quot;).widget([$SELF:PowerLimitOff],&amp;quot;selectnumbers,0,50,1000,0,lin&amp;quot;)|widget([$SELF:TimeStart],&amp;quot;time&amp;quot;).widget([$SELF:TimeEnd],&amp;quot;time&amp;quot;)\&lt;br /&gt;
|&amp;quot;&amp;lt;dd&amp;gt;Sommer, Winter Start / Ende&amp;lt;/dd&amp;gt;&amp;quot;| &amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([$SELF:TimeStartSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeStartWinter],&amp;quot;time&amp;quot;).|widget([$SELF:TimeEndSummer],&amp;quot;time&amp;quot;).widget([$SELF:TimeEndWinter],&amp;quot;time&amp;quot;)&lt;br /&gt;
attr Waschmaschine_PV_Perl verbose 3&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:48 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-09-26 13:47:21 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:45:40 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:38 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:52:45 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:42 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 12:27:19 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:23 Status_1 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 Status_2 -&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 17:32:31 TimeEndSummer 18:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:58 TimeEndWinter 16:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 07:17:00 TimeStart 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:48:05 TimeStartSummer 08:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-08-11 09:46:54 TimeStartWinter 10:00&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-11-01 09:21:25 ui_command_1 ---&lt;br /&gt;
setstate Waschmaschine_PV_Perl 2022-10-06 19:34:48 ui_command_1_before ---&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.55&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine&lt;br /&gt;
attr shelly03 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 432&lt;br /&gt;
attr shelly03 stateFormat {\&lt;br /&gt;
my $link = ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
my $e0 = sprintf(&amp;quot;%08.2f KWh&amp;quot;,ReadingsVal($name,&amp;quot;energy_Total&amp;quot;,0)/1000);;\&lt;br /&gt;
my $r0 = (ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:red&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:green&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;;;\&lt;br /&gt;
my $p0 = sprintf(&amp;quot;%06.1f Watt&amp;quot;,ReadingsVal($name,&amp;quot;power&amp;quot;,0));;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0 style=&#039;width: 100%&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;colgroup&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 30%;;&#039;&amp;gt;\&lt;br /&gt;
   &amp;lt;col span=&#039;1&#039; style=&#039;width: 20%;;&#039;&amp;gt;\&lt;br /&gt;
 &amp;lt;/colgroup&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:left&#039;&amp;gt;\&lt;br /&gt;
    WebLink: $link\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
     Waschmaschine Gesamt 0: $e0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;td style=&#039;text-align:right&#039;&amp;gt;\&lt;br /&gt;
    Relais 0: $r0 $p0&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/td&amp;gt;\&lt;br /&gt;
&amp;lt;/tr&amp;gt;\&lt;br /&gt;
&amp;lt;/table&amp;gt;\&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr shelly03 userReadings WebLink:network.* { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;na&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;&amp;quot;.$ip.&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
energy_Total:energy.* monotonic { ReadingsVal($name,&amp;quot;energy&amp;quot;,0) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,}) shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
\&lt;br /&gt;
Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]\&lt;br /&gt;
\&lt;br /&gt;
Version 2022.09.20 16:00\&lt;br /&gt;
Bis 3.9 Watt ist das Gerät aus, ab 4 Watt ist es eingeschaltet\&lt;br /&gt;
An  =&amp;gt; shelly03:power:\s([0-9]{2,}\.?[0-9]{0,}|[4-9]{1}\.?[0-9]{0,})\&lt;br /&gt;
Aus =&amp;gt; shelly03:power:\s([0-3]{1}\.?[0-9]{0,}|[0-3]{1})&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter event-on-update-reading power.*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 433&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Akku laden ===&lt;br /&gt;
In diesem Beispiel wird der Akku eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Akkus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Akkus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Wechselrichter]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Ch.eick</name></author>
	</entry>
</feed>